Dapper的Query需确保连接已打开、列名与属性名严格匹配(大小写敏感)、参数用匿名对象传递;QueryAsync须await且不可返回未物化的IEnumerable;QueryMultiple必须按SQL顺序依次读取结果集。

直接用 IDbConnection.Query 就能完成绝大多数查询,但前提是连接已打开、SQL 列名和属性名能对上、参数得用匿名对象传——漏掉任一环,结果就是 null、空列表或运行时炸。
Query 报 null 或默认值,八成是列名没对上
PostgreSQL、MySQL(lower_case_table_names=0)里,user_id 和 UserId 不等价;Dapper 默认按字面匹配(大小写敏感),不是靠驼峰转换。SQL Server 虽常不敏感,但别赌。
- 最省事:SQL 里加别名,
SELECT user_id AS UserId, full_name AS FullName FROM users - 想一劳永逸:用
SqlMapper.SetTypeMap(typeof(User), new ColumnAttributeTypeMapper,但得自己写()) ColumnAttributeTypeMapper类(它不读[Column],得手动映射) - 别指望
[JsonProperty]或 EF 的注解,Dapper 完全无视它们
QueryAsync 报 “Invalid operation on a closed reader”
这错误只说明一件事:你拿了 IEnumerable 出去,但 IDbConnection 在它被遍历前就关了。Dapper 的异步枚举是懒执行,底层 SqlDataReader 一关,再取就崩。
- 必须
await调用,不能丢掉async/await链 - 别在
using块外返回未物化的IEnumerable;要返回就.ToList()或.ToArray()先固化 - Web API 里直接
return Ok(conn.QueryAsync是错的——框架会等你返回后才消费枚举,此时连接早释放了(...))
QueryMultiple 多结果集必须顺序读,不能跳、不能乱
它不是智能分表,只是把一次响应里的多个结果集按 SQL 语句顺序切开。你写 SELECT Orders; SELECT OrderItems,就得先 multi.Read,再 multi.Read。中间插个 Read 或漏读一个,立刻抛 InvalidOperationException。
- 每个
Read返回的是() IEnumerable,不是单个对象;要取全部得.ToList() - 不支持 JOIN 后自动拆字段到多个类;想这么做,得靠 SQL 别名 + 多次
Read+ 手动组装 -
GridReader必须using,否则连接不释放,容易连爆
真正容易被忽略的点是:Dapper 从不管理连接生命周期,也不做任何 SQL 改写。你写的什么,它就发什么;你关连接的时机,直接决定结果能不能拿到。所谓“轻量”,本质是把控制权全交还给你,而不是替你兜底。











