You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core中AutoMapper ProjectTo未正确应用EF查询过滤条件问题

问题:EF Core查询结合AutoMapper ProjectTo后过滤条件失效

我使用.NET Core 7、Entity Framework Core 7.0.13和AutoMapper 12.0.3编写了如下EF查询:

var test = _context.Set<T>
    .AsNoTracking()
    .Include(m => m.MachineOperations!
        .Where(m =>
            m.InsertedAt.Date <= endDate.Date &&
            m.EndTime <= endDate.TimeOfDay &&
            m.InsertedAt.Date >= startDate.Date &&
            m.StartTime >= startDate.TimeOfDay))
    .ThenInclude(m => m.EggQuantities)
    .Where(m =>
        diffDays.Contains(m.WeekDay) &&
        m.MachineOperations!.Any() &&
        m.InitialProductionTime <= startDate.TimeOfDay &&
        m.FinalProductionTime >= startDate.TimeOfDay);

var test2 = _mapper.ProjectTo<MachineScheduleDataDto>(test);

问题:当传入本应无MachineOperation返回的参数时,原查询test结果为空,但经过ProjectTo转换后却意外出现数据。若在查询末尾添加.ToList()再转为AsQueryable()传入映射,过滤条件可正常工作,但此方式会查询所有实体属性,无法采用。

我的DTO类定义:

public record MachineScheduleDataDto
{
    public required ICollection<MachineOperationDto> MachineOperationsDto { get; set; }
}

public record MachineOperationDto
{
    public int MachineOperationId { get; set; }
    public EMachineStatus MachineStatus { get; set; }

    public virtual required MachineScheduleDataDto MachineScheduleDto { get; set; }
}

映射配置:

CreateMap<MachineSchedule, MachineScheduleDataDto>()
    .ForMember(p => p.MachineOperationsDto, opts => opts.MapFrom(m => m.MachineOperations));

CreateMap<MachineOperation, MachineOperationDto>()
   .ForMember(p => p.MachineScheduleDto, opts => opts.MapFrom(m => m.MachineSchedule));

原因分析

核心问题是EF Core的Include.Where导航属性过滤逻辑,不会被AutoMapper的ProjectTo自动继承:

  • Include.Where是对关联实体做查询级过滤,但AutoMapper生成投影查询时,会直接读取原始的MachineOperations导航属性,忽略你在Include中添加的过滤条件。
  • 原查询里的m.MachineOperations!.Any()判断的是经过Include过滤后的集合是否为空,但ProjectTo会把这个判断转换成对原始MachineOperations集合的检查,逻辑不一致,导致结果偏差。
  • 另外DTO中MachineOperationDto包含MachineScheduleDto,存在循环引用风险,也会干扰映射逻辑。

解决方案

方案1:在映射配置中显式添加过滤条件

修改映射规则,将过滤逻辑直接写入MapFrom,让ProjectTo把条件整合到最终SQL查询中:

CreateMap<MachineSchedule, MachineScheduleDataDto>()
    .ForMember(p => p.MachineOperationsDto, opts => opts.MapFrom((m, _, _, context) => 
        m.MachineOperations!
            .Where(mo => 
                mo.InsertedAt.Date <= ((DateTime)context.Items["EndDate"]).Date &&
                mo.EndTime <= ((DateTime)context.Items["EndDate"]).TimeOfDay &&
                mo.InsertedAt.Date >= ((DateTime)context.Items["StartDate"]).Date &&
                mo.StartTime >= ((DateTime)context.Items["StartDate"]).TimeOfDay)));

调用ProjectTo时传入上下文参数:

var test2 = _mapper.ProjectTo<MachineScheduleDataDto>(test, opt => 
{
    opt.Items["StartDate"] = startDate;
    opt.Items["EndDate"] = endDate;
});

方案2:直接在查询中做投影过滤(推荐)

放弃依赖Include,直接在查询里通过Select构建DTO结构,确保只查询需要的属性,同时避免映射逻辑冲突:

var query = _context.Set<MachineSchedule>()
    .AsNoTracking()
    .Where(m => 
        diffDays.Contains(m.WeekDay) &&
        m.MachineOperations!.Any(mo => 
            mo.InsertedAt.Date <= endDate.Date &&
            mo.EndTime <= endDate.TimeOfDay &&
            mo.InsertedAt.Date >= startDate.Date &&
            mo.StartTime >= startDate.TimeOfDay) &&
        m.InitialProductionTime <= startDate.TimeOfDay &&
        m.FinalProductionTime >= startDate.TimeOfDay)
    .Select(m => new MachineScheduleDataDto
    {
        MachineOperationsDto = m.MachineOperations!
            .Where(mo => 
                mo.InsertedAt.Date <= endDate.Date &&
                mo.EndTime <= endDate.TimeOfDay &&
                mo.InsertedAt.Date >= startDate.Date &&
                mo.StartTime >= startDate.TimeOfDay)
            .Select(mo => new MachineOperationDto
            {
                MachineOperationId = mo.MachineOperationId,
                MachineStatus = mo.MachineStatus
                // 移除循环引用的MachineScheduleDto,或添加Ignore配置
            }).ToList()
    });

额外优化:处理循环引用

修改映射配置,忽略会导致循环引用的属性:

CreateMap<MachineOperation, MachineOperationDto>()
   .ForMember(p => p.MachineScheduleDto, opts => opts.Ignore());

内容的提问来源于stack exchange,提问作者guirms

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 17:35:58