在Dapper .NET API中实现Media对象多层嵌套映射的问题
Dapper多层嵌套对象映射方案(适配Media类结构变更)
类结构示例
先明确修改后的实体类结构(对应业务需求的变更):
public class Media { public int MediaId { get; set; } public string Title { get; set; } // 原YoutubeID、VimeoID改为内部列表属性 public List<VideoId> VideoIds { get; set; } = new List<VideoId>(); } public class VideoId { public string YoutubeId { get; set; } public string VimeoId { get; set; } }
解决方案1:Multi-Mapping + 内存分组
利用Dapper的多对象映射能力获取扁平结果,再通过内存分组合并相同Media实例的嵌套列表:
// 关联查询SQL,确保返回Media主表+视频ID关联表的所有字段 var sql = @" SELECT m.MediaId, m.Title, v.YoutubeId, v.VimeoId FROM Media m LEFT JOIN VideoIds v ON m.MediaId = v.MediaId"; var mediaList = connection.Query<Media, VideoId, Media>( sql, // 临时映射:将每行的VideoId加入当前Media的列表 (media, videoId) => { if (videoId != null) media.VideoIds.Add(videoId); return media; }, // 指定拆分点:从YoutubeId字段开始,将结果映射到VideoId对象 splitOn: "YoutubeId" ) // 按MediaId分组,合并相同Media的VideoIds列表 .GroupBy(m => m.MediaId) .Select(g => { var mergedMedia = g.First(); mergedMedia.VideoIds = g.SelectMany(m => m.VideoIds).ToList(); return mergedMedia; }) .ToList();
解决方案2:手动构建嵌套结构(更灵活)
如果担心Dapper自动映射时重复创建Media实例,直接查询扁平数据后手动构建嵌套对象:
var flatResults = connection.Query<dynamic>(sql); var mediaDict = new Dictionary<int, Media>(); foreach (var item in flatResults) { int mediaId = item.MediaId; // 不存在则创建新的Media实例 if (!mediaDict.TryGetValue(mediaId, out var media)) { media = new Media { MediaId = mediaId, Title = item.Title, VideoIds = new List<VideoId>() }; mediaDict.Add(mediaId, media); } // 仅当视频ID不为空时添加到列表 if (!string.IsNullOrWhiteSpace(item.YoutubeId) || !string.IsNullOrWhiteSpace(item.VimeoId)) { media.VideoIds.Add(new VideoId { YoutubeId = item.YoutubeId, VimeoId = item.VimeoId }); } } // 最终得到嵌套结构的Media列表 var mediaList = mediaDict.Values.ToList();
关键注意点
- 字段映射匹配:确保SQL返回的字段名与类属性名一致,不一致时用SQL别名(如
SELECT youtube_id AS YoutubeId)或Dapper的[Column]特性标记。 - 空列表初始化:在Media类中提前初始化
VideoIds为空列表,避免JSON序列化时出现null值。 - splitOn参数:使用Multi-Mapping时,
splitOn必须指定嵌套对象的第一个字段,否则Dapper无法正确拆分映射。
内容的提问来源于stack exchange,提问作者Rajiv Ranjan
相关产品推荐
相关产品推荐

