Automapper通过关联关系使用ConstructUsing的投影异常问题
问题解决方法
你遇到的问题根源在于AutoMapper的ConstructUsing无法在EF的LINQ查询投影(ProjectTo)中正常工作——EF无法将ConstructUsing里的Mapper.Map调用转换成可执行的SQL语句,导致查询没有正确关联Software数据,最终返回空结果。
以下是几种可行的调整方案:
方案1:使用IncludeMembers复用已有映射
这是最简洁的方式,直接复用你已有的Software到SoftwareDTO的映射规则:
// 保留原有的Software到SoftwareDTO的映射 CreateMap<Software, SoftwareDTO>(); // 新增ChecklistLink到SoftwareDTO的映射,指定从Software属性继承映射规则 CreateMap<ChecklistLink, SoftwareDTO>() .IncludeMembers(src => src.Software);
之后直接执行查询即可,无需Select步骤:
var stuff = await ChecklistLink.AsNoTracking() .ProjectTo<SoftwareDTO>(config) .Distinct() .ToArrayAsync(cancellationToken);
IncludeMembers会让AutoMapper自动将ChecklistLink.Software的属性映射到SoftwareDTO,且能被EF转换成正确的SQL查询。
方案2:显式映射每个属性
如果不想用IncludeMembers,可以直接在ChecklistLink到SoftwareDTO的映射中指定每个属性的来源:
CreateMap<ChecklistLink, SoftwareDTO>() .ForMember(dest => dest.Id, opt => opt.MapFrom(src => src.Software.Id)) .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Software.Name)) // 依次映射SoftwareDTO的所有其他属性,来源都是src.Software对应字段
这种方式虽然繁琐,但能完全控制每个属性的映射逻辑,同样可以被EF正确解析为SQL投影。
方案3:先加载关联数据再映射(非投影方式)
如果不介意先从数据库加载ChecklistLink和关联的Software实体,再在内存中映射,可以用Include+内存映射:
var checklistLinks = await ChecklistLink.AsNoTracking() .Include(cl => cl.Software) .ToArrayAsync(cancellationToken); var stuff = checklistLinks .Select(cl => config.Mapper.Map<SoftwareDTO>(cl.Software)) .Distinct() .ToArray();
这种方式的缺点是会加载更多数据到内存,性能不如直接在数据库层面投影的方案。
内容的提问来源于stack exchange,提问作者Gargoyle
相关产品推荐
相关产品推荐

