使用AutoMapper映射EF Core多对多关系的问题咨询
问题分析与解决方案
你遇到的两个问题,我来逐一拆解并给出针对性的解决方案:
1. 其他属性为null的原因及修复
虽然你说模型属性名称和类型一致,但出现非多对多属性为null的情况,核心原因有两个:
- 你仅在父类
ClaseFabricante/ClaseConstructor的映射中处理了多对多路径,没有让AutoMapper完整处理底层Referencia实体的属性映射; - 可能EF查询时未正确加载所有关联实体的属性(比如未用
Include加载导航属性)。
修复步骤:
首先完善底层实体到ViewModel的映射,让AutoMapper同时处理同名属性和多对多关联:
config.CreateMap<ApplicationCore.Entities.ReferenciaFabricante, ApplicationCore.ViewModels.ReferenciaFabricante>() // 自动映射所有同名属性,手动处理多对多关联转换 .ForMember(dest => dest.ReferenciasConstructor, opt => opt.MapFrom(src => src.MontaReferenciasConstructor.Select(x => x.ReferenciaConstructor).ToList())); config.CreateMap<ApplicationCore.Entities.ReferenciaConstructor, ApplicationCore.ViewModels.ReferenciaConstructor>() .ForMember(dest => dest.ReferenciasFabricante, opt => opt.MapFrom(src => src.MontadaPorReferenciasFabricante.Select(x => x.ReferenciaFabricante).ToList()));
然后简化父类的映射配置,AutoMapper会自动复用上面的底层映射逻辑:
config.CreateMap<ApplicationCore.Entities.ClaseFabricante, ApplicationCore.ViewModels.ClaseFabricante>() // 仅保留你需要的额外路径映射,其他属性(包括ReferenciaFabricante)自动复用底层映射 .ForPath(dto => dto.ReferenciaFabricante.VersionesVehiculo, opt => opt.MapFrom(x => x.ReferenciaFabricante.MontaVersionesVehiculo.Select(y => y.VersionVehiculo).ToList())); config.CreateMap<ApplicationCore.Entities.ClaseConstructor, ApplicationCore.ViewModels.ClaseConstructor>(); // 无需额外配置,底层ReferenciaConstructor的映射已处理好多对多关联
最后确保EF查询时加载完整的关联数据:
var vClasesFabricante = dbContext.ClasesFabricante .Include(cf => cf.ReferenciaFabricante) .ThenInclude(rf => rf.MontaReferenciasConstructor) .ThenInclude(mrc => mrc.ReferenciaConstructor) .ToList();
2. 父模型ClaseFabricante与ClaseConstructor的映射是否需要中间模型配合?
是的,必须通过中间关联模型ReferenciaFabricanteTieneReferenciaConstructor来实现,但更合理的做法是在底层Referencia实体的映射中处理多对多转换,而不是在父类映射中直接写ForPath。
你之前的写法虽然能生效,但会导致代码冗余,且容易遗漏其他属性的映射。把多对多转换逻辑放在底层实体映射中,既符合AutoMapper的设计思想,也更便于维护。
完整优化后的映射初始化代码
(建议使用AutoMapper推荐的MapperConfiguration方式,Mapper.Initialize已过时)
var config = new MapperConfiguration(cfg => { // 1. 配置底层实体到ViewModel的映射 cfg.CreateMap<ApplicationCore.Entities.ReferenciaFabricante, ApplicationCore.ViewModels.ReferenciaFabricante>() .ForMember(dest => dest.ReferenciasConstructor, opt => opt.MapFrom(src => src.MontaReferenciasConstructor.Select(x => x.ReferenciaConstructor).ToList())); cfg.CreateMap<ApplicationCore.Entities.ReferenciaConstructor, ApplicationCore.ViewModels.ReferenciaConstructor>() .ForMember(dest => dest.ReferenciasFabricante, opt => opt.MapFrom(src => src.MontadaPorReferenciasFabricante.Select(x => x.ReferenciaFabricante).ToList())); // 2. 配置父类映射 cfg.CreateMap<ApplicationCore.Entities.ClaseFabricante, ApplicationCore.ViewModels.ClaseFabricante>() .ForPath(dto => dto.ReferenciaFabricante.VersionesVehiculo, opt => opt.MapFrom(x => x.ReferenciaFabricante.MontaVersionesVehiculo.Select(y => y.VersionVehiculo).ToList())); cfg.CreateMap<ApplicationCore.Entities.ClaseConstructor, ApplicationCore.ViewModels.ClaseConstructor>(); }); // 开发环境建议开启配置验证,提前发现映射问题 config.AssertConfigurationIsValid(); var mapper = config.CreateMapper(); // 使用映射 foreach (ApplicationCore.Entities.ClaseFabricante cfDAO in vClasesFabricante) { result.Add(mapper.Map<ApplicationCore.ViewModels.ClaseFabricante>(cfDAO)); }
内容的提问来源于stack exchange,提问作者SySc0d3r
相关产品推荐
相关产品推荐

