C# Dapper Contrib使用方法 C#如何简化Dapper的CRUD操作

来源:这里教程网 时间:2026-02-21 17:41:58 作者:

为什么直接用
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)]
,尤其是布尔、数值、日期等易被误判的类型。

如何让
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 参数的重载方法。

相关推荐