Dapper映射失败主因是列名与属性名大小写不匹配,需用SetTypeMap显式绑定或SQL别名;QueryAsync报错因连接提前关闭,须await并确保生命周期覆盖结果消费;多表查询可用Query配合splitOn切分;参数化查询防SQL注入且正确处理null。

查出来的数据总是 null?检查 SqlMapper.SetTypeMap 和字段名大小写
默认情况下,Dapper 要求数据库列名(column name)和 C# 属性名(property name)**完全匹配(含大小写)**,尤其在 PostgreSQL 或启用了 `lower_case_table_names=0` 的 MySQL 中容易翻车。SQL Server 通常不敏感,但别依赖它。
常见错误现象:SELECT user_id, full_name FROM users 映射到 class User { public int UserId { get; set; } public string FullName { get; set; } } 时,两个属性全是 null 或 0。
- 最稳方案:用
SqlMapper.SetTypeMap显式绑定,比如SqlMapper.SetTypeMap(typeof(User), new ColumnAttributeTypeMapper<user>());</user> - 更轻量做法:改 SQL 别名,
SELECT user_id AS UserId, full_name AS FullName FROM users - 注意:Dapper 不读取
[Column]或[JsonProperty],只认列名或别名
QueryAsync<t></t> 报错 “Invalid operation on a closed reader” 怎么办
这基本等于你在 IDbConnection 已关闭后,还试图消费异步查询结果——比如忘了 await,或者 connection 被 using 提前释放了。
使用场景:Web API 返回 IEnumerable<t></t> 但没立刻遍历;或在 using 块外返回了查询结果。
- 必须
awaitQueryAsync,不能丢掉async/await链 - connection 生命周期要覆盖整个结果消费过程;若需延迟执行,用
ToList()或ToArray()立即物化 - 别返回
IEnumerable<t></t>给调用方自行 foreach —— Dapper 的IEnumerable是“懒加载”,底层 reader 一关就崩
想用 Dapper 查多表关联,又不想手写 JOIN 映射?试试 Query<t1 t2 treturn></t1>
Dapper 原生支持多类型映射,但条件很具体:SQL 必须按顺序 SELECT 所有字段,且类型参数顺序必须和 SELECT 列顺序一致。
示例:查用户 + 对应部门信息,SQL 写成 SELECT u.id, u.name, d.id, d.name FROM users u JOIN depts d ON u.dept_id = d.id,那么调用得这样:
connection.Query<User, Dept, UserWithDept>(
sql,
(u, d) => new UserWithDept { User = u, Dept = d },
splitOn: "d.id"
);splitOn 参数不是表名,是第二个类型(Dept)第一个字段的列名(这里是 d.id),Dapper 靠它切分结果集。
- 如果第二张表字段名和第一张重复(比如都叫
id),必须用别名,且splitOn值要对应别名,如SELECT u.id, u.name, d.id AS dept_id, d.name AS dept_name ...,然后splitOn: "dept_id" - 不支持三张及以上表直接链式映射;超过两张,建议用
QueryMultiple或分步查 - 性能上和手写 JOIN 无差异,只是省了手动赋值
WHERE 条件里传入 null 导致 SQL 报错?别硬拼字符串
Dapper 支持参数化查询,但新手常犯的错是把 null 直接塞进 SQL 字符串,比如 "WHERE name = '" + inputName + "'",结果 inputName == null 就变 WHERE name = '' 或语法错误。
- 永远用参数占位符:
WHERE name = @name,然后传new { name = inputName } -
null会自动转为 SQL 的NULL,且能正确走索引(取决于数据库) - 需要“忽略 null 条件”时,SQL 得写成
WHERE (@name IS NULL OR name = @name),而不是在 C# 里拼 SQL - 慎用
IN动态列表:用WHERE id IN @ids+new { ids = new[] { 1, 2, 3 } },Dapper 会自动展开参数,不用自己拼逗号串
Dapper 的映射逻辑非常直白,但也正因如此,它不会替你猜意图——列名对不上、连接没 await、参数传错类型,都会立刻暴露。最容易被忽略的是:它不缓存映射关系(除非你手动设 SqlMapper.AddTypeMap),每次泛型查询都做一次反射绑定,高频小对象建议预热或考虑静态映射器。


















