Automapper投影场景下如何实现EF Account到AccountDto的自定义映射逻辑
解决方案
因为 Linq to EF 投影要求映射逻辑必须能被转换为可解析的表达式树,自定义 ValueResolver 属于运行时逻辑无法被EF识别,你可以直接在 MapFrom 中编写内联的判断逻辑,或者将逻辑封装为可复用的表达式:
方案1:直接编写内联映射逻辑(最简单)
直接在映射配置里写判断逻辑,EF可以直接解析为SQL语句:
profile.CreateMap<Account, AccountDto>() .ForMember(dest => dest.PortfolioType, opt => opt.MapFrom(src => src.PortfolioTypeAXref != null && src.PortfolioTypeAXref.PortfolioTypeAId.HasValue ? PortfolioType.A : src.PortfolioTypeBXref != null && src.PortfolioTypeBXref.PortfolioTypeBId.HasValue ? PortfolioType.B : src.PortfolioTypeCXref != null && src.PortfolioTypeCXref.PortfolioTypeCId.HasValue ? PortfolioType.C : src.PortfolioTypeDXref != null && src.PortfolioTypeDXref.PortfolioTypeDId.HasValue ? PortfolioType.D : PortfolioType.Unknown )) .ForMember(dest => dest.PortfolioId, opt => opt.MapFrom(src => src.PortfolioTypeAXref != null && src.PortfolioTypeAXref.PortfolioTypeAId.HasValue ? src.PortfolioTypeAXref.PortfolioTypeAId : src.PortfolioTypeBXref != null && src.PortfolioTypeBXref.PortfolioTypeBId.HasValue ? src.PortfolioTypeBXref.PortfolioTypeBId : src.PortfolioTypeCXref != null && src.PortfolioTypeCXref.PortfolioTypeCId.HasValue ? src.PortfolioTypeCXref.PortfolioTypeCId : src.PortfolioTypeDXref != null && src.PortfolioTypeDXref.PortfolioTypeDId.HasValue ? src.PortfolioTypeDXref.PortfolioTypeDId : null ));
方案2:封装可复用的表达式(适合多场景复用逻辑)
如果你不想重复写判断逻辑,可以把判断逻辑封装为独立的表达式,再引入到映射配置中:
// 先定义可复用的判断表达式 public static readonly Expression<Func<Account, (PortfolioType Type, long? Id)>> PortfolioInfoExpr = src => src.PortfolioTypeAXref != null && src.PortfolioTypeAXref.PortfolioTypeAId.HasValue ? (PortfolioType.A, src.PortfolioTypeAXref.PortfolioTypeAId) : src.PortfolioTypeBXref != null && src.PortfolioTypeBXref.PortfolioTypeBId.HasValue ? (PortfolioType.B, src.PortfolioTypeBXref.PortfolioTypeBId) : src.PortfolioTypeCXref != null && src.PortfolioTypeCXref.PortfolioTypeCId.HasValue ? (PortfolioType.C, src.PortfolioTypeCXref.PortfolioTypeCId) : src.PortfolioTypeDXref != null && src.PortfolioTypeDXref.PortfolioTypeDId.HasValue ? (PortfolioType.D, src.PortfolioTypeDXref.PortfolioTypeDId) : (PortfolioType.Unknown, null); // 映射配置中引入表达式 profile.CreateMap<Account, AccountDto>() .ForMember(dest => dest.PortfolioType, opt => opt.MapFrom(PortfolioInfoExpr.Combine(x => x.Type))) .ForMember(dest => dest.PortfolioId, opt => opt.MapFrom(PortfolioInfoExpr.Combine(x => x.Id)));
注:上面用到的
Combine是表达式树拼接的扩展方法,如果你不需要复用逻辑,直接用方案1即可。
验证
配置完成后直接用 ProjectTo<AccountDto>() 投影即可,EF会自动把上面的判断逻辑转换为SQL的CASE WHEN语句,不会触发客户端评估。
内容的提问来源于stack exchange,提问作者Josh
相关产品推荐
相关产品推荐

