Dapper如何映射到嵌套的复杂类型 Dapper深层对象映射

来源:这里教程网 时间:2026-02-21 17:35:46 作者:

Dapper 映射嵌套复杂类型,核心靠 MultiMapping(多对象映射)和 自定义 TypeHandler 两类机制。它不自动递归解析三层以上对象,也不支持原生的“深度导航属性”映射(比如

Post.Owner.Address.City
),但通过组合策略完全可以实现清晰、可控的深层结构。

用 MultiMapping 处理 1 对 1 和 1 对多嵌套

这是最常用也最直接的方式,适用于两层或手动组装三层结构:

1 对 1(如 Post → User):用
Query<t1 t2 tresult></t1>
+
splitOn
指定分割列(如
"UserId"
),再在委托里赋值:
(post, user) => { post.Owner = user; return post; }
1 对多(如 Post → List:不能直接用泛型 Query,需借助字典缓存父对象,遍历结果集时按外键聚合子项。常见写法是先查主表+关联表联合结果,再用
Lookup
GroupBy
分组组装
3 级嵌套(如 Post → User → Profile):可扩展为
Query<post user profile post></post>
,最多支持 7 个泛型参数,
splitOn
需传入逗号分隔字符串,如
"UserId,ProfileId"
,Dapper 会依序切分字段段

用 TypeHandler 支持 JSON 字段反序列化

当深层结构不适合拆成多表 JOIN(比如用户配置、订单明细项列表),推荐把嵌套部分存为 JSON 字段,再用自定义

TypeHandler<t></t>
自动转换:

数据库字段类型设为
VARCHAR(MAX)
或原生
JSON
(SQL Server 2016+ / MySQL 5.7+ / PostgreSQL)
编写
JsonTypeHandler<address></address>
类,重写
Parse
SetValue
,用
System.Text.Json
处理序列化
注册一次:
SqlMapper.AddTypeHandler(new JsonTypeHandler<address>());</address>
实体中直接声明
public Address ShippingAddress { get; set; }
,Dapper 读写时自动处理

用 CustomTypeMap 处理继承或动态类型

当嵌套对象类型不固定(如基类

Notification
下有
EmailNotif
SmsNotif
子类),需靠
ITypeMap
实现运行时类型选择:

根据数据库中标识字段(如
NotifType
值为
"Email"
)决定实例化哪个子类
继承
DefaultTypeMap
或实现
ITypeMap
,在
GetMemberMaps
中注入逻辑
调用
SqlMapper.SetTypeMap(typeof(Notification), yourCustomMap)
全局生效
这样嵌套属性(如
User.PreferredNotif
)就能返回具体子类型,而非空基类

避坑要点:别依赖自动深度映射

Dapper 不会像 EF Core 那样扫描导航属性并自动 JOIN。以下情况必须手动干预:

列名冲突(如两张表都有
Id
)→ 务必用 SQL 别名:
p.Id as PostId, u.Id as UserId
,并让
splitOn
对应别名
NULL 关联数据(如未设置作者的帖子)→ 委托函数里判空:
post.Owner = user ?? null;
性能敏感场景 → 避免 N+1 查询,优先用单次 JOIN + MultiMapping,而不是循环查子对象 字段过多影响映射 → 只 SELECT 实际需要的列,避免
SELECT *
导致 splitOn 错位

基本上就这些。Dapper 的嵌套映射不是“全自动”,但每一步都透明可控,写清楚 splitOn、写好映射委托、配对好 TypeHandler,深层结构也能很稳。

相关推荐