Entity Framework中ThenInclude过滤及结合AutoMapper ProjectTo的实现
解决方案
问题1:Include/ThenInclude过滤不生效的原因及修复
你最初的代码未过滤SectorBenchmark,是因为EF Core中过滤Include集合的特性需要EF Core 5.0+版本支持,且必须触发查询执行(如调用ToList())。未执行查询时仅构建了查询对象,不会应用过滤逻辑;添加ToList()后查询执行,过滤规则才会生效,这也是你后续解决该问题的核心原因。
正确的EF Core过滤Include写法(确保版本符合要求):
var filteredBenchmarks = _dbContext.ProjectBenchmarks .Where(pb => pb.ProjectId == targetProjectId) // 先过滤目标项目的基准 .Include(b => b.GlobalBenchmark) .ThenInclude(gb => gb.SectorBenchmarks.Where(sb => sb.SectorId == sectorId)) .ToList();
问题2:结合AutoMapper的ProjectTo实现过滤+映射
当使用ProjectTo进行DTO投影时,不能依赖Include/ThenInclude的过滤逻辑(因为ProjectTo会生成独立的SELECT语句,忽略Include中的过滤规则),可通过以下两种方式实现需求:
方式1:映射配置中传入动态参数(推荐)
在AutoMapper配置中定义支持动态参数的映射,查询时传入行业ID:
- 配置映射规则:
CreateMap<GlobalBenchmark, GlobalBenchmarkDTO>() .ForMember(dest => dest.SectorBenchmarks, opt => opt.MapFrom((src, _, __, context) => src.SectorBenchmarks.Where(sb => sb.SectorId == (int)context.Items["SectorId"]))); CreateMap<ProjectBenchmark, ProjectBenchmarkDTO>() .IncludeMembers(pb => pb.GlobalBenchmark);
- 执行带参数的投影查询:
var sectorId = targetProjectSectorId; // 项目所属行业ID var result = _dbContext.ProjectBenchmarks .Where(pb => pb.ProjectId == targetProjectId) .ProjectTo<ProjectBenchmarkDTO>(_mapper.ConfigurationProvider, opt => opt.Items["SectorId"] = sectorId) .ToList();
方式2:手动投影过滤
直接在查询中手动构建DTO,显式过滤SectorBenchmark,无需依赖AutoMapper的集合映射规则:
var sectorId = targetProjectSectorId; var result = _dbContext.ProjectBenchmarks .Where(pb => pb.ProjectId == targetProjectId) .Select(pb => new ProjectBenchmarkDTO { // 映射ProjectBenchmark字段 Id = pb.Id, Name = pb.Name, // ...其他字段 GlobalBenchmark = new GlobalBenchmarkDTO { Id = pb.GlobalBenchmark.Id, Name = pb.GlobalBenchmark.Name, // ...其他字段 SectorBenchmarks = pb.GlobalBenchmark.SectorBenchmarks .Where(sb => sb.SectorId == sectorId) .Select(sb => new SectorBenchmarkDTO { Id = sb.Id, SectorId = sb.SectorId, // ...其他字段 }).ToList() } }) .ToList();
内容的提问来源于stack exchange,提问作者Lukas Grecu
相关产品推荐
相关产品推荐

