Dapper 不自动映射 DTO,因其设计轻量、显式、高性能,仅支持字段名匹配的简单映射;AutoMapper 负责复杂对象转换,二者需手动协作,推荐先用 Dapper 查询再由 AutoMapper 映射。
直接用 Dapper 查询数据库后,结果默认是 IDataReader 或动态对象(如 dynamic),它本身不提供自动映射到 DTO 的能力。Dapper 也不内置类似 AutoMapper 的对象映射逻辑 —— 所以“Dapper 自动映射 DTO”其实是靠你手动调用 AutoMapper,而不是 Dappe
r 主动触发它。
为什么不能让 Dapper “自动”调用 AutoMapper?
Dapper 的设计哲学是轻量、显式、高性能。它只负责把 SQL 结果按字段名(或列序)映射到强类型对象的 同名 public 属性 上,不介入业务层的转换逻辑(比如属性重命名、类型转换、嵌套对象组装、条件映射等)。AutoMapper 则专注在对象到对象的复杂转换上,两者职责不同,天然互补但需手动桥接。
推荐做法:查完再映射(最清晰可控)
这是最常用、最易调试、也最符合分层原则的方式:先用 Dapper 获取领域模型(如 Entity)或匿名对象,再交给 AutoMapper 转成 DTO。
- 查询时用 Dapper 映射到实体类(或匿名对象),保持 SQL 和数据访问层干净
- 在应用服务层或查询处理器中,调用
mapper.Map(entity) - 如果 DTO 字段少、结构简单,也可以用 Dapper 直接查 DTO(前提是字段名完全匹配):
conn.Query("SELECT Id, Name FROM Users")
进阶技巧:封装一个带 AutoMapper 的 QueryHandler
避免重复写“查 + 映射”,可封装通用方法:
public async TaskQuerySingleAsync ( string sql, object param = null) where TEntity : class { var entity = await _connection.QuerySingleAsync (sql, param); return _mapper.Map (entity); }
这样业务代码就变成:var userDto = await handler.QuerySingleAsync
注意避坑点
-
别在 Dapper 的
Query中传 DTO 类型,除非字段 100% 匹配(比如 DTO 没有构造函数参数、没私有 setter、所有属性名和 SQL 列名一致) - AutoMapper 配置要提前注册好(如
CreateMap),否则运行时报错() - 若 SQL 返回多表 JOIN 数据,DTO 含嵌套对象(如
UserDto.Profile),Dapper 原生不支持自动展开;此时要么用Query手动组合,要么改用 AutoMapper 的 ProjectTo(配合 EF Core)—— Dapper 不支持 ProjectTo
基本上就这些。Dapper 和 AutoMapper 不是“绑定关系”,而是“协作关系”:一个管快读,一个管巧转。用好它们的关键是明确分工,不越界,不强求自动化。








