dapper核心是为idbconnection扩展方法,增删改用execute(返回影响行数),查用query(需字段名严格匹配),插入获自增id用executescalar或returning,异步需匹配支持真异步的驱动。

怎么用 Dapper 执行最简单的增删改查
直接上手不用写一堆样板代码——Dapper 的核心就是给 IDbConnection 扩展方法,所有操作都基于一个打开的连接对象。别想着先配个“Dapper上下文”,它压根不维护状态。
常见错误:调用 Query<t></t> 时传了 INSERT 语句,结果返回空集合还纳闷为啥没报错。记住:Query 只处理 SELECT;增删改一律用 Execute。
-
Execute:用于INSERT/UPDATE/DELETE,返回受影响行数(int) -
Query<t></t>:查单条或多条,自动映射到T类型(字段名需匹配) -
QueryFirstOrDefault<t></t>:查不到时返回default(T),比Query+.FirstOrDefault()少一次枚举 - 参数必须是匿名对象或强类型对象,不能传
Dictionary<string object></string>(除非你自己封装扩展)
Execute 返回 0 是不是一定失败了
不一定。比如 UPDATE users SET name=@name WHERE id=@id 中,如果 @id 对应记录不存在,Execute 就返回 0,但 SQL 执行本身是成功的,没有异常。
所以别只看返回值是否 > 0 就断定“成功”,得结合业务逻辑判断:你预期影响几行?要不要抛异常?
- 插入后想获取自增 ID?用
ExecuteScalar配合SELECT SCOPE_IDENTITY()(SQL Server)或LAST_INSERT_ROWID()(SQLite) - PostgreSQL 要用
RETURNING id子句,直接在INSERT里写,然后用QuerySingle<int></int> - 批量执行多个语句?Dapper 不支持事务自动包裹,得自己用
BeginTransaction包一层
字段名对不上导致查询结果全是默认值怎么办
这是新手掉进最多的一坑:Query<user></user> 映射失败,User.Name 始终是 null 或 0,但 SQL 里明明有 user_name 字段。
Dapper 默认严格按列名匹配属性名,不自动做下划线转驼峰、大小写忽略等。它不会猜你想要什么。
- 最简单:SQL 里用别名对齐,比如
SELECT user_name AS Name FROM users - 全局配置映射规则?可以,但得在应用启动时设置
SqlMapper.SetTypeMap,且只对后续查询生效 - 不想改 SQL 也不动全局配置?用
Query<dynamic></dynamic>先确认数据能取出来,再手动赋值 - 注意:
Query<t></t>不会报错说“找不到 Name 属性”,而是静默跳过——这点和 EF 完全不同
为什么 QueryAsync 有时比同步还慢
异步不是银弹。如果你用的是传统 ADO.NET 驱动(比如老版本 System.Data.SqlClient),它的 ExecuteReaderAsync 实际是线程池模拟的,并发高时反而更容易堆积线程。
真正受益于 QueryAsync 的场景,是数据库驱动本身支持真正的异步 I/O(如 Microsoft.Data.SqlClient 2.1+、Npgsql、MySqlConnector)。
- 检查你引用的驱动包名和版本:
Microsoft.Data.SqlClient≠System.Data.SqlClient - ASP.NET Core 6+ 默认启用异步管道,但若你在非 await 上下文(比如构造函数、静态初始化器)里调用
await QueryAsync,会死锁 - 简单读取少量数据?同步
Query更快,少一层调度开销
字段映射、执行路径、驱动行为——这些细节不摸清,光套“教程代码”只会让问题更模糊。











