AutoMapper使用IncludeMembers映射List成员报缺失映射错误如何解决
AutoMapper 嵌套图书集合展平映射配置方案
问题复现
首先定义实体与DTO:
public class Book { public int Id { get; set; } public string Title { get; set; } public List<Book> RelatedBooks { get; set; } } public class BookDto { public int Id { get; set; } public string Title { get; set; } }
错误配置写法:
CreateMap<Book, BookDto>() .IncludeMembers(s => s.RelatedBooks);
运行时抛出异常:
Missing map from System.Collections.Generic.IEnumerable
1[Book] to BookDto. Create using CreateMap<IEnumerable1, BookDto>
预期实现逻辑:将源Book集合中所有父级Book、以及每个Book下挂载的RelatedBooks嵌套集合,全部展平为一层,统一映射为BookDto集合,等价于以下手写逻辑:
public List<BookDto> GetAllBooks() { var listBookAll = new List<Book>(); // 数据源为接口返回结果 var bookParent = listBookAll.Select(s => new BookDto { Id = s.Id, Title = s.Title, }); var relatedBooks = listBookAll.SelectMany(s => s.RelatedBooks).Select(s2 => new BookDto { Id = s2.Id, Title = s2.Title }); var finalBooks = new List<BookDto>(); finalBooks.AddRange(bookParent); finalBooks.AddRange(relatedBooks); return finalBooks; }
错误原因
IncludeMembers的设计用途是单对象属性合并,不是集合展平:它的作用是把指定的嵌套对象的属性,合并映射到当前生成的单个目标对象实例上,适用于类似「源User包含HomeAddress、WorkAddress两个嵌套对象,目标UserDto要直接打平包含两类地址字段」的场景。
之前的写法相当于告知AutoMapper:映射单个Book到BookDto时,除了Book自身的属性,还要把RelatedBooks这个集合整体当成一个源对象,把它的属性也合并到当前BookDto实例中,自然会因为集合无法映射为单个BookDto实例抛出缺映射的错误。
正确实现
第一步:配置基础单实体映射
首先配置单Book到BookDto的常规映射,不需要加IncludeMembers:
CreateMap<Book, BookDto>();
第二步:选择集合展平方式
根据复用需求二选一即可:
- 方式1:映射前手动展平(灵活无额外配置,适合单次使用场景)
映射前先用LINQ把父级Book和所有嵌套RelatedBooks合并为单层Book序列,再交给AutoMapper统一映射,逻辑和手写实现完全对齐,注意加空判断避免RelatedBooks为null触发空引用:public List<BookDto> GetAllBooks(IMapper mapper, List<Book> listBookAll) { // 展平:每个父Book + 其下所有关联Book 拼成单序列 var flattenBooks = listBookAll .SelectMany(book => new[] { book } .Concat(book.RelatedBooks ?? Enumerable.Empty<Book>())); return mapper.Map<List<BookDto>>(flattenBooks); } - 方式2:全局配置集合映射规则(适合多次复用场景)
新增集合类型的转换规则,后续所有映射List<Book>到List<BookDto>的场景都会自动展平,不需要重复写展平逻辑:
配置完成后直接调用映射即可:// 基础单实体映射 CreateMap<Book, BookDto>(); // 集合级自动展平配置 CreateMap<List<Book>, List<BookDto>>() .ConvertUsing((source, context) => { var flattenSource = source .SelectMany(book => new[] { book } .Concat(book.RelatedBooks ?? Enumerable.Empty<Book>())) .ToList(); return context.Mapper.Map<List<BookDto>>(flattenSource); });// 自动展平映射,无需额外处理 var result = mapper.Map<List<BookDto>>(listBookAll);
内容的提问来源于stack exchange,提问作者ddxx
相关产品推荐
相关产品推荐

