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

Automapper升级:DateTime转int映射与投影区分实现问题

问题描述

我正在将.NET Framework项目从AutoMapper 4.1.1升级至10.0.0,遇到了一个棘手的问题。AutoMapper 10里ConvertUsing和ProjectUsing已经合并,但我需要区分普通内存映射和IQueryable投影两种场景:

  • 当映射是IQueryable投影时,DateTime转int需要用SqlFunctions计算分钟数(因为要生成SQL语句)
  • 当是普通内存对象映射时,直接用TimeOfDay.TotalMinutes做简单转换就行

但现在每个映射只能配置一个ConvertUsing,之前尝试用旧的ProjectUsing或者在ConvertUsing里判断是否是IQueryable场景都没用。

原4.1.1版本的配置代码如下:

CreateMap<DateTime?, int>().ConvertUsing(x => x.HasValue ? System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", x.Value).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", x.Value).Value : 0);
CreateMap<DateTime, int>().ConvertUsing(x => System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", x).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", x).Value);
CreateMap<DateTime?, int>().ConvertUsing(x => Convert.ToInt32(x.HasValue ? x.Value.TimeOfDay.TotalMinutes : 0));
CreateMap<DateTime, int>().ConvertUsing(x => Convert.ToInt32(x.TimeOfDay.TotalMinutes));
解决方案

在AutoMapper 10+中,可以通过以下两种方式实现区分场景的映射:

方法1:利用映射上下文判断场景

使用ConvertUsing的重载,接收ResolutionContext参数,通过context.IsProjection属性判断当前是否处于投影场景:

// 可空DateTime转int
CreateMap<DateTime?, int>().ConvertUsing((src, dest, context) =>
{
    if (context.IsProjection)
    {
        return src.HasValue 
            ? System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", src.Value).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", src.Value).Value 
            : 0;
    }
    else
    {
        return Convert.ToInt32(src.HasValue ? src.Value.TimeOfDay.TotalMinutes : 0);
    }
});

// 非空DateTime转int
CreateMap<DateTime, int>().ConvertUsing((src, dest, context) =>
{
    if (context.IsProjection)
    {
        return System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", src).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", src).Value;
    }
    else
    {
        return Convert.ToInt32(src.TimeOfDay.TotalMinutes);
    }
});

方法2:分离投影与内存映射配置

先配置基础的内存映射逻辑,再为投影场景单独覆盖映射规则:

// 基础内存映射配置
CreateMap<DateTime?, int>().ConvertUsing(x => Convert.ToInt32(x.HasValue ? x.Value.TimeOfDay.TotalMinutes : 0));
CreateMap<DateTime, int>().ConvertUsing(x => Convert.ToInt32(x.TimeOfDay.TotalMinutes));

// 为IQueryable投影场景覆盖逻辑
CreateMap<DateTime?, int>()
    .ForMember(dest => dest, opt => opt.MapFrom(src => 
        src.HasValue 
            ? System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", src.Value).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", src.Value).Value 
            : 0));

CreateMap<DateTime, int>()
    .ForMember(dest => dest, opt => opt.MapFrom(src => 
        System.Data.Entity.SqlServer.SqlFunctions.DatePart("HOUR", src).Value * 60 + System.Data.Entity.SqlServer.SqlFunctions.DatePart("MINUTE", src).Value));

AutoMapper处理IQueryable投影时会优先解析MapFrom的表达式树生成SQL,内存映射则使用ConvertUsing的逻辑。

注意事项

  • 确保AutoMapper版本为10.0.0及以上,IsProjection属性在此版本已可用
  • 使用SqlFunctions时,需确保项目引用了EntityFramework相关包,且EF能正确解析函数生成SQL

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 11:40:22