AutoMapper映射嵌套列表时重置目标类未定义字段的问题
解决方案
1. 显式配置AutoMapper忽略CriteriaId字段
在AutoMapper的Profile配置类中,针对嵌套的MaterialLocaleDto到MaterialLocaleEntity的映射,明确忽略CriteriaId字段,避免映射时覆盖原有值:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<MaterialDto, MaterialEntity>(); CreateMap<MaterialLocaleDto, MaterialLocaleEntity>() .ForMember(dest => dest.CriteriaId, opt => opt.Ignore()); } }
2. 使用UseDestinationValue保留原有字段值
如果需要更明确地表示要保留目标实体的现有值,可以用UseDestinationValue替代Ignore(),效果一致但语义更清晰:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<MaterialDto, MaterialEntity>(); CreateMap<MaterialLocaleDto, MaterialLocaleEntity>() .ForMember(dest => dest.CriteriaId, opt => opt.UseDestinationValue()); } }
3. 精细控制集合映射(适配新增/删除场景)
如果需要同时处理集合中元素的新增、删除和更新,可通过关联ID匹配现有实体,仅更新需要的字段:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<MaterialDto, MaterialEntity>() .ForMember(dest => dest.Locales, opt => opt.MapFrom((src, dest) => // 匹配已有ID的元素,更新指定字段 src.Locales.Join(dest.Locales, srcLocale => srcLocale.MaterialLocaleId, destLocale => destLocale.MaterialLocaleId, (srcLocale, destLocale) => _mapper.Map(srcLocale, destLocale)) // 新增DTO中存在但数据库没有的元素 .Concat(src.Locales.Where(srcLocale => !dest.Locales.Any(destLocale => destLocale.MaterialLocaleId == srcLocale.MaterialLocaleId)) .Select(srcLocale => _mapper.Map<MaterialLocaleEntity>(srcLocale))) )); CreateMap<MaterialLocaleDto, MaterialLocaleEntity>() .ForMember(dest => dest.CriteriaId, opt => opt.MapFrom((src, dest) => dest?.CriteriaId ?? 0)); } }
问题原因说明
AutoMapper对根对象的更新默认仅映射源对象存在的属性,不会覆盖目标中无对应源属性的字段。但对于集合类型,默认会遍历每个元素进行完整映射,未配置的字段会被重置为类型默认值(如int的0),因此必须显式配置保留原有值。
内容的提问来源于stack exchange,提问作者BMErEr
相关产品推荐
相关产品推荐

