Dapper不支持全自动深度嵌套映射,但可通过Multi-Mapping(如Query配合splitOn)实现一对一级联;一对多用QueryMultiple分步查询+内存关联;三层及以上需组合多步查询并手动组装,核心是显式控制、避免N+1、注意别名与空值处理。
Dapper 本身不支持全自动的深度嵌套对象映射(比如 User 包含 Address,Address 又包含 City),但通过组合使用 Query 的多映射(Multi-Mapping)和手动组装逻辑,完全可以优雅地实现嵌套对象填充。
这是最常用、最清晰的方式,适用于主从结构(如 Order → OrderItem,User → Profile)。关键在于 SQL 中用 JOIN 拉平数据,并用 splitOn 参数告诉 Dapper 从哪一列开始是第二个对象的字段。
示例:映射 User 及其关联的 Department
var sql = @"
SELECT u.Id, u.Name, u.Email,
d.Id as DeptId, d.Name as DeptName, d.Code
FROM Users u
LEFT JOIN Departments d ON u.DeptId = d.Id";
var users = connection.Query(
sql,
(user, dept) =>
{
user.Department = dept; // 手动赋值
return user;
},
splitOn: "DeptId"
).ToList();
d.Id as DeptId,所以写 "DeptId")SqlMapper.AddTypeMap 自定义映射)User),可在此完成任意组装逻辑一对多不能靠单条 JOIN 搞定(会产生笛卡尔积),推荐用 QueryMultiple 执行多个语句,再在内存中关联。
var sql = @"
SELECT * FROM Users WHERE IsActive = 1;
SELECT u.Id as UserId, p.* FROM Posts p
INNER JOIN Users u ON p.UserId = u.
Id
WHERE u.IsActive = 1;";
using var multi = connection.QueryMultiple(sql);
var users = multi.Read().ToList();
var posts = multi.Read().ToList();
// 手动按 UserId 分组挂载
var lookup = posts.GroupBy(p => p.UserId).ToDictionary(g => g.Key, g => g.ToList());
foreach (var user in users)
{
user.Posts = lookup.GetValueOrDefault(user.Id, new List());
}
Dictionary> 做 O(1) 关联,比循环嵌套查找快得多没有内置三元映射,但可以拆解为两步:先用 Query 得到带 Department 的用户,再单独查 Company 并批量挂载。
// 第一步:查 User + Department(同上) var usersWithDepts = connection.Query(...).ToList(); // 第二步:提取所有 DeptId,批量查 Company var deptIds = usersWithDepts .Where(u => u.Department != null) .Select(u => u.Department.Id) .Distinct() .ToArray();
if (deptIds.Length > 0) { var companies = connection.Query
( "SELECT * FROM Companies WHERE Id IN @ids", new { ids = deptIds } ).ToDictionary(c => c.Id); foreach (var user in usersWithDepts) { if (user.Department != null && companies.TryGetValue(user.Department.Id, out var company)) { user.Department.Company = company; } }}
- 避免为每个 Department 单独查 Company(N+1)
- 利用
ToDictionary实现快速反查,保持线性时间复杂度- 注意空值判断,防止 NullReferenceException
小技巧:用匿名对象或 ValueTuple 简化中间步骤
当嵌套层级多、临时组装频繁时,可用匿名类型过渡,让代码更松耦合:
var result = connection.Query( sql, (u, d, c) => (u, d, c), splitOn: "DeptId,CompanyId" ).ToList(); // 再统一组装成最终对象 var finalUsers = result.Select(x => { x.Item1.Department = x.Item2; x.Item2.Company = x.Item3; return x.Item1; }).ToList();
- 适合一次性复杂映射,不想提前定义中间 DTO 类
- ValueTuple(C# 7+)比匿名类更轻量,且可序列化
- 仍需明确指定
splitOn字段名,顺序必须与泛型参数一致基本上就这些。Dapper 的哲学是“显式优于隐式”,它不隐藏 SQL 和映射逻辑,反而让你对性能和行为有完全掌控。嵌套映射不复杂,但容易忽略
splitOn的大小写、别名一致性、空值处理这些细节。
# app # ai # c# # sql # int # 循环 # Lambda # 泛型 # 对象 # 多个 # 笛卡尔 # 不支持 # 的是 # 这是 # 字段名 # 让你 # 第一个 # 在此 # 适用于
相关文章: 建站主机SSH密钥生成步骤及常见问题解答? 如何通过VPS搭建网站快速盈利? ,网页ppt怎么弄成自己的ppt? 设计网站制作公司有哪些,制作网页教程? 如何实现建站之星域名转发设置? 实现点击下箭头变上箭头来回切换的两种方法【推荐】 黑客如何通过漏洞一步步攻陷网站服务器? 建站之星导航菜单设置与功能模块配置全攻略 宝华建站服务条款解析:五站合一功能与SEO优化设置指南 香港服务器租用费用高吗?如何避免常见误区? 网站制作网站,深圳做网站哪家比较好? 网站制作知乎推荐,想做自己的网站用什么工具比较好? 专业制作网站的公司哪家好,建立一个公司网站的费用.有哪些部分,分别要多少钱? 建站之星价格显示格式升级,你的预算足够吗? 音乐网站服务器如何优化API响应速度? linux top下的 minerd 木马清除方法 免费制作小说封面的网站有哪些,怎么接网站批量的封面单? 如何选择美橙互联多站合一建站方案? 建站主机类型有哪些?如何正确选型 再谈Python中的字符串与字符编码(推荐) 建站主机选哪种环境更利于SEO优化? 制作网站软件推荐手机版,如何制作属于自己的手机网站app应用? 如何通过WDCP绑定主域名及创建子域名站点? 如何在西部数码注册域名并快速搭建网站? 建站主机选购指南与交易推荐:核心配置解析 电商网站制作多少钱一个,电子商务公司的网站制作费用计入什么科目? 如何通过.red域名打造高辨识度品牌网站? 如何制作算命网站,怎么注册算命网站? ,有什么在线背英语单词效率比较高的网站? 建站之星如何实现PC+手机+微信网站五合一建站? 建站OpenVZ教程与优化策略:配置指南与性能提升 中山网站推广排名,中山信息港登录入口? 黑客入侵网站服务器的常见手法有哪些? 如何在阿里云ECS服务器部署织梦CMS网站? C#如何序列化对象为XML XmlSerializer用法 c# 在ASP.NET Core中管理和取消后台任务 如何选择可靠的免备案建站服务器? 宝塔建站助手安装配置与建站模板使用全流程解析 如何在Windows虚拟主机上快速搭建网站? 巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成 如何快速搭建高效可靠的建站解决方案? 香港服务器网站生成指南:免费资源整合与高速稳定配置方案 建站主机如何选?性能与价格怎样平衡? 详解免费开源的.NET多类型文件解压缩组件SharpZipLib(.NET组件介绍之七) 建站之星logo尺寸如何设置最合适? 建站之星在线版空间:自助建站+智能模板一键生成方案 如何在阿里云香港服务器快速搭建网站? 如何安全更换建站之星模板并保留数据? 微信h5制作网站有哪些,免费微信H5页面制作工具? 公司网站制作需要多少钱,找人做公司网站需要多少钱?
*请认真填写需求信息,我们会在24小时内与您取得联系。