已配置Ignore,AutoMapper仍清空集合的原因求助
问题场景
使用AutoMapper 10.1.1,因无法升级至.NET Standard 2.1,无法更新到AutoMapper 12.0.1。在多层映射(FromA→ToA,嵌套FromB→ToB)时,已配置Ignore()的ToB.MemberC(ICollection<ToC>类型)被自动设置为空数组,其他Ignore()属性正常保留目标值。
涉及类结构:
// 源端 class FromA { // ...其他属性... public FromB MemberB { get; set; } } class FromB { // ...其他属性... } // 目标端 class ToA { // ...其他属性... public ToB MemberB { get; set; } } class ToB { // ...其他属性... public ICollection<ToC> MemberC { get; set; } } class ToC { // ...其他属性... }
原映射配置:
// 自定义成员值解析器 internal class TypeMappingMemberValueResolver<TSource, TDestination, TSourceMember, TDestinationMember> : IMemberValueResolver<TSource, TDestination, TSourceMember, TDestinationMember> { public TDestinationMember Resolve(TSource source, TDestination destination, TSourceMember sourceMember, TDestinationMember destMember, ResolutionContext context) { return context.Mapper.Map<TSourceMember, TDestinationMember>(sourceMember, destMember); } } // 映射配置 CreateMap<FromA, ToA>() // ...其他配置... .ForMember(to => to.MemberB, opt => opt.MapFrom(new TypeMappingMemberValueResolver<FromA, ToA, FromB, ToB>(src => src.MemberB))) // ...其他配置... CreateMap<FromB, ToB>() // ...其他配置... .ForMember(to => to.MemberC, opt => opt.Ignore())
执行映射后,instanceOfToA.MemberB.MemberC被清空为空数组,而非保留原有值。
问题分析
在AutoMapper 10.x版本中,多层嵌套映射结合自定义成员解析器时,集合类型的Ignore()规则可能被内部的集合默认处理逻辑覆盖。当通过顶层映射间接触发嵌套映射时,AutoMapper会对目标集合执行初始化或清空操作,忽略已配置的保留规则。
解决方案
1. 移除自定义成员值解析器,使用默认嵌套映射
自定义解析器可能触发了额外的映射逻辑,改用AutoMapper默认的嵌套映射即可避免该问题:
CreateMap<FromA, ToA>() // ...其他配置... // 无需自定义解析器,AutoMapper会自动使用已注册的FromB→ToB映射 .ForMember(to => to.MemberB, opt => opt.MapFrom(src => src.MemberB)) // 甚至可省略该行,因为属性名完全匹配,AutoMapper会自动映射
2. 强化ToB.MemberC的忽略配置
结合Precondition、UseDestinationValue和Ignore,强制AutoMapper不修改目标集合:
CreateMap<FromB, ToB>() // ...其他配置... .ForMember(to => to.MemberC, opt => { opt.Precondition((src, dest) => false); // 永远不执行映射 opt.UseDestinationValue(); // 强制保留目标值 opt.Ignore(); })
3. 在顶层映射中直接忽略深层集合属性
跳过中间层,直接在FromA→ToA的映射中配置忽略MemberB.MemberC:
CreateMap<FromA, ToA>() // ...其他配置... .ForMember(to => to.MemberB.MemberC, opt => opt.Ignore())
4. 手动处理嵌套对象映射,绕过自动集合逻辑
通过AfterMap手动执行FromB→ToB的映射,避免顶层映射触发的额外集合处理:
CreateMap<FromA, ToA>() // ...其他配置... .ForMember(to => to.MemberB, opt => opt.Ignore()) // 先忽略自动映射 .AfterMap((src, dest) => { if (src.MemberB != null && dest.MemberB != null) { // 手动映射到已存在的目标对象 Mapper.Map(src.MemberB, dest.MemberB); } })
最终建议
优先尝试方案1或方案4,这两个方案能直接规避AutoMapper旧版本的集合处理bug。若所有配置方案均无效,则只能考虑升级至.NET Standard 2.1并使用AutoMapper 12.0.1,该版本已修复多个嵌套映射和集合处理的问题。
内容的提问来源于stack exchange,提问作者yvsean

