AutoMapper集合映射时如何保留源中不存在的目标属性值
AutoMapper集合映射保留目标对象原有属性解决方案
问题根因
AutoMapper执行集合映射时的默认行为是清空目标集合后新增映射生成的新元素,而非更新目标集合的已有元素。你直接调用_mapper.Map(srcList, destList)时,原有的SCS_OUT_ManifestItem实例会被全部删除,替换为新创建的实例,源DTO中不存在的ManifestId属性自然会被初始化为默认空Guid。
而你循环遍历逐个匹配ItemId再执行单个对象映射时,是直接更新已有实例的对应属性,未被映射的属性就会保留原值。
解决方案
方案1:配置集合映射匹配规则(推荐)
在AutoMapper的Profile配置中,指定集合元素的匹配逻辑,让AutoMapper自动按ItemId匹配现有元素执行更新,而非替换整个集合:
// 单个对象映射配置 CreateMap<UpdateItemDetailDto, SCS_OUT_ManifestItem>() // 显式忽略不需要映射的属性,避免意外覆盖 .ForMember(dest => dest.ManifestId, opt => opt.Ignore()); // 集合映射配置,按ItemId匹配元素 CreateMap<List<UpdateItemDetailDto>, ICollection<SCS_OUT_ManifestItem>>() .EqualityComparison((srcItem, destItem) => srcItem.ItemId == destItem.ItemId);
配置完成后,直接调用原有集合映射代码即可保留ManifestId属性:
_mapper.Map(updateShipmentDetailDto.ItemDetails, manifest.SCS_OUT_ManifestItems);
方案2:封装集合映射扩展方法(无需修改全局配置)
如果不想修改全局AutoMapper配置,可以把循环匹配逻辑封装为通用扩展方法,灵活适配不同的匹配规则:
public static class MapperExtension { public static void UpdateCollection<TSrc, TDest>(this IMapper mapper, IEnumerable<TSrc> sourceList, ICollection<TDest> targetList, Func<TSrc, TDest, bool> matchPredicate) { foreach (var srcItem in sourceList) { var matchedDest = targetList.FirstOrDefault(d => matchPredicate(srcItem, d)); if (matchedDest != null) { mapper.Map(srcItem, matchedDest); } // 如需新增源存在、目标不存在的元素,可在此处补充新增逻辑 } } }
调用方式如下:
_mapper.UpdateCollection(updateShipmentDetailDto.ItemDetails, manifest.SCS_OUT_ManifestItems, (src, dest) => src.ItemId == dest.ItemId);
注意事项
- 用作匹配键的字段(如
ItemId)需要保证在集合内唯一,避免匹配错误 - 若有多个不需要映射的目标属性,统一在单个对象映射配置中用
Ignore显式声明,避免后续迭代中属性名重复导致的意外覆盖
内容的提问来源于stack exchange,提问作者thanzeel
相关产品推荐
相关产品推荐

