如何使用AutoMapper将嵌套集合属性投影到DTO并返回投影集合?
问题:AutoMapper映射嵌套集合到DTO集合(支持EF服务器端投影)
需求:将源模型LargeEntity的List<ExampleModelContainer>类型属性ModelEntries,投影为目标模型LargeEntityDto的List<ExampleModelDto>类型属性Models,且要求大部分投影操作在EF服务器端完成。
源模型
public class ExampleModel { public int Id { get; set; } public float Something { get; set; } public string Info { get; set; } = ""; } public class ExampleModelContainer { public int Id { get; set; } public ExampleModel Model { get; set; } = null!; } public class LargeEntity { public int Id { get; set; } public List<ExampleModelContainer> ModelEntries { get; set; } = null!; }
目标模型
public class ExampleModelDto { public float Something { get; set; } public string Info { get; set; } = ""; } public class LargeEntityDto { public int Id { get; set; } public List<ExampleModelDto> Models { get; set; } = null!; }
尝试的配置及异常
尝试通过定义ExampleModelContainer到ExampleModel的转换间接映射,但配置验证失败:
public class AutoMapperProfile : Profile { public AutoMapperProfile() { CreateMap<ExampleModel, ExampleModelDto>(); // 尝试将容器转换为模型,再自动转为DTO,但失败 CreateMap<ExampleModelContainer, ExampleModel>() .ConvertUsing(x => x.Model); CreateMap<LargeEntity, LargeEntityDto>() .ForMember(x => x.Models, opt => opt.MapFrom(y => y.ModelEntries)); } }
异常信息:
Unhandled exception. AutoMapper.AutoMapperConfigurationException: The following member on AutoMapperExps.Models.LargeEntityDto cannot be mapped: Models Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type AutoMapperExps.Models.LargeEntityDto. Context: Mapping to member Models from AutoMapperExps.Models.LargeEntity to AutoMapperExps.Models.LargeEntityDto Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown. at AutoMapper.Configuration.ConfigurationValidator.AssertConfigurationIsValid(IEnumerable`1 typeMaps) at AutoMapper.Configuration.ConfigurationValidator.AssertConfigurationExpressionIsValid(IEnumerable`1 typeMaps) at AutoMapper.MapperConfiguration.AssertConfigurationIsValid() at Program.Main(String[] args) in D:\Experiments\AutoMapperExps\Program.cs:line 1
解决方案
直接在MapFrom中通过LINQ选择容器内的Model属性,结合已有的ExampleModel到ExampleModelDto的映射,既满足配置验证,又支持EF服务器端投影:
public class AutoMapperProfile : Profile { public AutoMapperProfile() { // 定义基础模型到DTO的映射,EF可解析该表达式 CreateMap<ExampleModel, ExampleModelDto>(); CreateMap<LargeEntity, LargeEntityDto>() .ForMember(dest => dest.Models, // 直接从每个容器中提取Model,AutoMapper会自动应用ExampleModel→ExampleModelDto的映射 opt => opt.MapFrom(src => src.ModelEntries.Select(container => container.Model))); } }
说明
- 避免自定义转换:之前使用
ConvertUsing的方式会生成客户端评估代码,无法被EF转换成SQL,同时AutoMapper无法自动将List<ExampleModelContainer>转换为List<ExampleModelDto>,导致配置验证失败。 - 服务器端投影支持:上述配置中的
Select(container => container.Model)是EF可解析的表达式,结合ExampleModel到ExampleModelDto的映射,AutoMapper会生成完整的服务器端投影SQL,只查询Something和Info等必要字段。 - 配置验证通过:该配置可以正常通过
AssertConfigurationIsValid()验证,无映射错误。
内容的提问来源于stack exchange,提问作者anon
相关产品推荐
相关产品推荐

