dapper.contrib 报“id property not found”因默认只识别名为 id 的 int/long 主键;需用 [key] 显式标记主键(支持 guid 等),[explicitkey] 用于手动赋值主键,[computed] 标注数据库计算列。

为什么直接用 Dapper.Contrib 会报错“ID property not found”
因为 Dapper.Contrib 要求实体类必须有明确的主键标识,且默认只认名为 Id 的 int 或 long 类型属性。如果你的主键叫 UserId、OrderId,或者类型是 Guid,不加标注就会失败。
解决方式是显式标记主键:
- 用
[Key]特性标注主键字段(支持Guid、int、long等) - 用
[ExplicitKey]标注需要手动赋值的主键(比如数据库不自增,由代码生成Guid) - 用
[Computed]标注数据库计算列(如CreatedAt默认GETDATE()),避免插入时传入
示例:
[Table("Users")]
public class User
{
[Key]
public Guid Id { get; set; } // 不再依赖命名或类型约束
public string Name { get; set; }
[Computed]
public DateTime CreatedAt { get; set; }
}
Insert 和 Update 为什么会忽略某些字段
Dapper.Contrib 默认跳过 null 值、空字符串、0 值(对数值类型)以及未标记为可写([Write(true)])的字段。它不是全量映射,而是按“有意义变更”策略处理。
常见陷阱:
-
bool IsActive = false被当成“未设置”,插入时不会写入数据库 —— 必须加[Write(true)] -
string Code = ""(空字符串)被跳过,而你其实想存空值 —— 改用string.Empty不起作用,需显式赋值并确保字段可写 -
DateTime? LastLogin = null是安全的,但DateTime LastLogin = default(即0001-01-01)会被写入,可能不是你想要的
推荐做法:所有需要持久化的字段,显式加 [Write(true)],尤其是布尔、数值、日期等易被误判的类型。
95Shop可以免费下载使用,是一款仿醉品商城网店系统,内置SEO优化,具有模块丰富、管理简洁直观,操作易用等特点,系统功能完整,运行速度较快,采用ASP.NET(C#)技术开发,配合SQL Serve2000数据库存储数据,运行环境为微软ASP.NET 2.0。95Shop官方网站定期开发新功能和维护升级。可以放心使用! 安装运行方法 1、下载软件压缩包; 2、将下载的软件压缩包解压缩,得到we
如何让 Dapper.Contrib 支持复合主键或非标准表名
它原生不支持复合主键 —— 这是硬限制。一旦实体有多个 [Key] 字段,Insert/Get 等方法会抛异常或行为未定义。必须改用单主键设计,或退回到原生 Dapper 手写 SQL。
表名和列名控制靠两个特性:
-
[Table("user_info")]控制映射的物理表名(不加则用类名小写) -
[Column("user_name")]控制字段对应列名(不加则用属性名小写)
注意:[Column] 不影响参数绑定顺序,只影响生成的 SQL 中的列名;如果字段名含大小写或特殊字符,必须加该特性,否则生成的 SQL 可能语法错误(如列名未加括号或引号)。
性能与线程安全要注意什么
Dapper.Contrib 内部用了静态缓存(如 SqlMapperExtensions.GetTableInfo 缓存类型映射),所以首次调用 Insert 较慢,后续极快。但这也意味着:一旦类结构变更(如加字段、改 [Key]),缓存不会自动刷新 —— 开发期容易查不到新字段,需重启应用或手动清缓存(无公开 API,实际中建议避免热更新实体)。
它本身是线程安全的,但依赖的 IDbConnection 不是。别把同一个连接实例跨线程复用;每个操作应使用新打开的连接或通过 using 确保释放。
最常被忽略的一点:它不支持事务跨方法传播。比如你在一个 TransactionScope 里调用两次 Insert,它们各自开连接、各自提交 —— 实际上没在同一个事务里。必须手动传入共享的 IDbConnection 和 IDbTransaction,并调用带 transaction 参数的重载方法。









