dapper 不自动打开连接,需显式调用 connection.open();列名与属性名必须精确匹配(大小写敏感),推荐 sql 中用 as 别名;queryasync() 需 await 物化,避免返回未执行的 ienumerable;多结果集须用 querymultiple() 并严格按顺序 read()。

必须显式调用 connection.Open(),否则所有查询都会直接抛出 InvalidOperationException: Connection is not open —— Dapper 从不帮你开连接,这是它“轻量”的代价,也是你最容易栽的第一个坑。
为什么 Query<t>()</t> 返回空列表或全是默认值
根本原因不是 SQL 写错了,而是数据库列名和 C# 属性名没对上。Dapper 默认走字面精确匹配(大小写敏感),不自动转下划线、不读 [Column]、不认 [JsonProperty]。
- PostgreSQL 或 MySQL(
lower_case_table_names=0)里,user_id和UserId完全不等价 - SQL Server 虽常不敏感,但别赌——不同 collation 或显式设置可能翻车
- 最稳做法:SQL 里加
AS别名,例如SELECT user_id AS UserId, created_at AS CreatedAt FROM users - 想全局统一?得手动注册映射器:
SqlMapper.SetTypeMap(typeof(User), new ColumnAttributeTypeMapper<user>())</user>,但 Dapper 不带现成实现,得自己写
QueryAsync<t>()</t> 报 “Invalid operation on a closed reader” 怎么办
这错误只说明一件事:你返回了未物化的 IEnumerable<t></t>,而 IDbConnection 在它被遍历前就关了。Dapper 的异步枚举是懒执行,底层 SqlDataReader 一关,再取就崩。
- 必须
await调用,不能丢掉async/await链 - 别在
using块外返回未物化的IEnumerable<t></t>;要返回就先.ToList()或.ToArray() - Web API 里写
return Ok(conn.QueryAsync<user>())</user>是错的——框架消费时连接早释放了 - 如果真需要延迟执行,确保连接生命周期覆盖整个消费过程,而不是靠“运气”
多结果集必须用 QueryMultiple(),且 Read<t>()</t> 顺序不能错
QueryMultiple() 不是智能分表,只是按 SQL 语句顺序把一次响应切开。你写 SELECT Orders; SELECT OrderItems,就得先 multi.Read<order>()</order>,再 multi.Read<orderitem>()</orderitem>。
- 中间插个
Read<string>()</string>或漏读一个,立刻抛InvalidOperationException - 每个
Read<t>()</t>返回的是IEnumerable<t></t>,不是单个对象;要取首项得接.FirstOrDefault() -
GridReader必须using包裹,否则连接不释放,容易连爆 - SQL 中多个查询必须用分号分隔,不能靠注释或换行
真正容易被忽略的点是:Dapper 从不管理连接生命周期,也不做任何 SQL 改写。你写的什么,它就发什么;你关连接的时机,直接决定结果能不能拿到。所谓“轻量”,本质是把控制权全交还给你,而不是替你兜底。










