如何避免AutoMapper忽略成员时将值设为null?
问题分析与解决方案
你遇到的核心问题是:先调用ForAllMembers(opt => opt.Ignore())会全局忽略所有成员映射,即便后续显式配置了ForPath,也可能因为AutoMapper的执行逻辑导致配置的字段未生效,最终得到全null的映射结果。下面是高效的解决方式:
方案1:调整配置顺序,用ForAllOtherMembers替代ForAllMembers
不要一开始就忽略所有成员,而是先配置需要映射的字段,最后忽略未显式配置的其余成员。这样既保证了指定字段的正常映射,又避免了不必要的字段覆盖。
示例配置代码:
// TechDataVariant -> TechData 映射 var variants = CreateMap<TechDataVariant, TechData>(); variants.ForPath(dest => dest.Acceleration.Label, opt => opt.MapFrom(source => source.Acceleration.Label)) .ForPath(dest => dest.Acceleration.Value, opt => opt.MapFrom(source => source.Acceleration.Value)) .ForAllOtherMembers(opt => opt.Ignore()); // Other1 -> TechData 映射 var other1 = CreateMap<Other1, TechData>(); other1.ForPath(dest => dest.Other1.Label, opt => opt.MapFrom(source => source.SomethingElse1.Label)) .ForPath(dest => dest.Other1.Value, opt => opt.MapFrom(source => source.SomethingElse2.Value)) .ForAllOtherMembers(opt => opt.Ignore()); // Other2 -> TechData 映射 var other2 = CreateMap<Other2, TechData>(); other2.ForPath(dest => dest.Other2.Label, opt => opt.MapFrom(source => source.SomethingElse2.Label)) .ForPath(dest => dest.Other2.Value, opt => opt.MapFrom(source => source.SomethingElse2.Value)) .ForAllOtherMembers(opt => opt.Ignore());
方案2:直接映射到已存在的TechData对象(适配你的AfterMap场景)
在AfterMap中,不要创建新的TechData对象,而是直接将各个源对象映射到已有的dest.TechData上。这样每个映射只会更新你配置好的字段,保留目标对象中原有的其他值,避免被覆盖为null。
修改后的AfterMap代码:
CreateMap<MyDTO, MyTarget>() .ForMember(/* 你的其他属性配置 */) .AfterMap((src, dest, context) => { if (dest.TechData == null) dest.TechData = new TechData(); // 直接映射到已有的dest.TechData,仅更新配置字段 context.Mapper.Map(src.TechDataVariant, dest.TechData); context.Mapper.Map(src.other1, dest.TechData); context.Mapper.Map(src.other2, dest.TechData); });
额外优化:用Profile组织映射规则
将所有TechData相关的映射配置放到单独的Profile类中,让代码结构更清晰,便于后续维护:
public class TechDataProfile : Profile { public TechDataProfile() { // TechDataVariant -> TechData CreateMap<TechDataVariant, TechData>() .ForPath(dest => dest.Acceleration.Label, opt => opt.MapFrom(source => source.Acceleration.Label)) .ForPath(dest => dest.Acceleration.Value, opt => opt.MapFrom(source => source.Acceleration.Value)) .ForAllOtherMembers(opt => opt.Ignore()); // Other1 -> TechData CreateMap<Other1, TechData>() .ForPath(dest => dest.Other1.Label, opt => opt.MapFrom(source => source.SomethingElse1.Label)) .ForPath(dest => dest.Other1.Value, opt => opt.MapFrom(source => source.SomethingElse2.Value)) .ForAllOtherMembers(opt => opt.Ignore()); // Other2 -> TechData CreateMap<Other2, TechData>() .ForPath(dest => dest.Other2.Label, opt => opt.MapFrom(source => source.SomethingElse2.Label)) .ForPath(dest => dest.Other2.Value, opt => opt.MapFrom(source => source.SomethingElse2.Value)) .ForAllOtherMembers(opt => opt.Ignore()); } }
初始化AutoMapper时添加该Profile:
var mapperConfig = new MapperConfiguration(cfg => { cfg.AddProfile<TechDataProfile>(); cfg.CreateMap<MyDTO, MyTarget>() .ForMember(/* 你的其他属性配置 */) .AfterMap((src, dest, context) => { if (dest.TechData == null) dest.TechData = new TechData(); context.Mapper.Map(src.TechDataVariant, dest.TechData); context.Mapper.Map(src.other1, dest.TechData); context.Mapper.Map(src.other2, dest.TechData); }); });
内容的提问来源于stack exchange,提问作者CodingLittle
相关产品推荐
相关产品推荐

