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

为何AutoMapper的ProjectTo不调用自定义方法,Map却正常?

为什么AutoMapper的ProjectTo不调用自定义方法,但Map可以?

核心原因是两者的执行机制完全不同:

1. ProjectTo的执行逻辑

ProjectTo是基于LINQ to Entities的查询转换,它会把你的映射配置转换成对应的SQL查询语句,直接在数据库层面完成数据筛选、投影操作。

EF Core只能解析特定的表达式树(比如标准LINQ方法、实体属性访问等),你定义的AddShiftCondition是自定义静态方法,EF Core无法把这个方法的逻辑翻译成对应的SQL语句,因此这个方法不会被执行,AutoMapper会直接跳过这个无法转换的映射规则,改用默认的集合映射逻辑。

另外注意:用ProjectTo时不需要写Include,AutoMapper会根据映射关系自动生成必要的Join语句,手动加Include反而可能带来额外的性能开销。

2. Map的执行逻辑

Map是内存中的对象转换:你先通过EF Core把实体数据从数据库加载到内存(比如FirstOrDefault()已经完成了数据库查询并把数据拉到内存),之后AutoMapper在内存中对这些对象进行映射,此时自定义方法就是普通的内存操作,自然可以正常调用执行。

解决方案:让过滤逻辑支持EF Core解析

要让ProjectTo能处理你的过滤需求,需要把逻辑改成EF Core能解析的表达式,而不是自定义方法:

方法1:直接在映射中写表达式并传递参数

var configuration = new MapperConfiguration(cfg =>
{
    cfg.CreateProjection<MachineSchedule, MachineScheduleDataDto>()
        .ForMember(m => m.ShiftsDto, opts => opts.MapFrom((src, _, __, context) => 
        {
            var targetShiftType = (EShiftType?)context.Items["ShiftType"];
            return targetShiftType.HasValue 
                ? src.Shifts.Where(s => s.Type == targetShiftType.Value) 
                : src.Shifts;
        }))
        .ForMember(m => m.ScheduledStopsDto, opts => opts.MapFrom(m => m.ScheduledStops))
        .ForMember(m => m.MachineOperationsDto, opts => opts.MapFrom(m => m.MachineOperations));

    // 其他投影配置...
});

// 使用时传入shiftType参数
var test = queryMapper.ProjectTo<MachineScheduleDataDto>(
    _typedContext!.AsNoTracking().OrderBy(m => m.MachineScheduleId),
    opt => opt.Items["ShiftType"] = shiftType.Value
);

方法2:封装可解析的表达式树(适合复杂逻辑)

如果过滤逻辑比较复杂,可以封装成表达式树供EF Core解析:

// 定义返回表达式树的方法
private static Expression<Func<ICollection<Shift>, EShiftType?, IEnumerable<Shift>>> GetShiftFilterExpr()
{
    return (shifts, targetType) => 
        targetType.HasValue 
            ? shifts.Where(s => s.Type == targetType.Value) 
            : shifts;
}

// 配置投影
var configuration = new MapperConfiguration(cfg =>
{
    var shiftFilter = GetShiftFilterExpr();
    cfg.CreateProjection<MachineSchedule, MachineScheduleDataDto>()
        .ForMember(m => m.ShiftsDto, opts => opts.MapFrom((src, _, __, context) => 
            shiftFilter.Compile()(src.Shifts, (EShiftType?)context.Items["ShiftType"])))
        // 其他映射...
});

// 使用方式和方法1一致
var test = queryMapper.ProjectTo<MachineScheduleDataDto>(
    _typedContext!.AsNoTracking().OrderBy(m => m.MachineScheduleId),
    opt => opt.Items["ShiftType"] = shiftType.Value
);

内容的提问来源于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 09:07:43