简体   繁体   English

不调用 AutoMapper ConvertUsing

[英]AutoMapper ConvertUsing is not called

I have simple task: just map one class to another.我有一个简单的任务:只是 map 一个 class 到另一个。 For some fields I have complex logic, depends on 2 or more fields, so, I try to use ConvertUsing ( https://docs.automapper.org/en/stable/Custom-type-converters.html )对于某些字段,我有复杂的逻辑,取决于 2 个或更多字段,因此,我尝试使用ConvertUsing ( https://docs.automapper.org/en/stable/Custom-type-converters.html )

I use AutoMapper 10.0.0我使用 AutoMapper 10.0.0

My code is:我的代码是:

Source class:来源 class:

public class DeviceStatusHistory
{
    public DeviceStatusHistory()
    {
        DateChange = DateTime.UtcNow;
    }

    public int Id { get; set; }
    public int DeviceId { get; set; }
    public virtual Device Device { get; set; }

    public int? RequestId { get; set; }
    public virtual DeviceManagementRequest Request { get; set; }

    public DeviceStatus OldStatus { get; set; }
    public DeviceStatus NewStatus { get; set; }
    public string Notes { get; set; }
    public DateTime DateChange { get; set; }
}

DTO class: DTO class:

public class DeviceChangeStatusDto
{
    public int DeviceId { get; set; }
    public string CarrierName { get; set; }
    public string DeviceName { get; set; }
    public string DeviceIMEI { get; set; }
    public string OldStatus { get; set; }
    public string NewStatus { get; set; }
    public string Reason { get; set; }
    public DateTime DateChange { get; set; }
}

and Automapper class:和自动映射器 class:

public class AutoMapperEfDeviceManagement : AutoMapper.Profile
{
    public AutoMapperEfDeviceManagement()
    {
        CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>().ConvertUsing<DeviceChangeStatusConverter>();
    }
}

where DeviceChangeStatusConverter is defined as:其中DeviceChangeStatusConverter定义为:

public class DeviceChangeStatusConverter : ITypeConverter<DeviceStatusHistory, DeviceChangeStatusDto>
{
    public DeviceChangeStatusDto Convert(DeviceStatusHistory source, DeviceChangeStatusDto destination, ResolutionContext context)
    {
        destination = new DeviceChangeStatusDto
        {
            CarrierName = source.Device.CarrierId.HasValue ? source.Device.Carrier.Name : null,
            DeviceId = source.DeviceId,
            DateChange = source.DateChange,
            DeviceIMEI = source.Device.IMEI,
            DeviceName = source.Device.GetFriendlyDetailedName(),
            NewStatus = CommonHelper.SplitByWords(source.NewStatus.ToString())
        };

        // some complex logic here

        return destination;
    }
}

but when I try to map it:但是当我尝试 map 时:

var list = _context.DeviceStatusHistory
.Where(a => ((int)a.NewStatus < 100) && a.DateChange.Date == date.Date)
.ProjectTo<DeviceChangeStatusDto>(_mapperConfig)
.ToList();

where _mapperConfig is:其中_mapperConfig是:

        _mapperConfig = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<AutoMapperEfDeviceManagement>();
        });

It maps looks like it was declared simple as:它映射看起来像被声明为简单:

CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>();

so, only the same properties are mapped, converter is not called (debugger says the same).所以,只有相同的属性被映射,转换器没有被调用(调试器说同样的)。 What is wrong?怎么了?

ADDED:添加:

approach like:方法如:

        CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>()
            .ConvertUsing((source, destination) =>
            {
                destination.CarrierName = source.Device.CarrierId.HasValue ? source.Device.Carrier.Name : null;

does not work too也不行

TL;DR TL;博士

It is not a bug, it's a known limitation.这不是错误,而是已知的限制。 Basically AutoMapper can't convert some custom method into SQL (or translate it into the form which will allow your ORM to translate that into SQL) so it can't use your type converter in ProjectTo .基本上 AutoMapper 无法将某些自定义方法转换为 SQL (或将其转换为允许您的 ORM 将其转换为 SQL 的形式),因此它不能在ProjectTo中使用您的类型转换器。

A little bit more details:更多细节:

From thedocumentation :文档中:

The .ProjectTo<OrderLineDTO>() will tell AutoMapper 's mapping engine to emit a select clause to the IQueryable that will inform entity framework that it only needs to query the Name column of the Item table, same as if you manually projected your IQueryable to an OrderLineDTO with a Select clause. .ProjectTo<OrderLineDTO>()将告诉AutoMapper的映射引擎向IQueryable发出select子句,该子句将通知实体框架它只需要查询Item表的Name列,就像您手动投影您的IQueryable到带有Select子句的OrderLineDTO

And from Custom Type Conversion section:并来自自定义类型转换部分:

Occasionally, you need to completely replace a type conversion from a source to a destination type.有时,您需要完全替换从源类型到目标类型的类型转换。 In normal runtime mapping, this is accomplished via the ConvertUsing method.在正常的运行时映射中,这是通过ConvertUsing方法完成的。 To perform the analog in LINQ projection, use the ConvertUsing method: cfg.CreateProjection<Source, Dest>().ConvertUsing(src => new Dest { Value = 10 });要在 LINQ 投影中执行模拟,请使用ConvertUsing方法: cfg.CreateProjection<Source, Dest>().ConvertUsing(src => new Dest { Value = 10 });
The expression-based ConvertUsing is slightly more limited than Func -based ConvertUsing overloads as only what is allowed in an Expression and the underlying LINQ provider will work.基于表达式的ConvertUsing比基于FuncConvertUsing重载稍受限制,因为只有Expression中允许的内容和基础 LINQ 提供程序才能工作。

And Supported mapping options :支持的映射选项

Not all mapping options can be supported, as the expression generated must be interpreted by a LINQ provider.并非所有映射选项都可以支持,因为生成的表达式必须由 LINQ 提供程序解释。 Only what is supported by LINQ providers is supported by AutoMapper: AutoMapper 仅支持 LINQ 提供程序支持的内容:

  • MapFrom (Expression-based) MapFrom(基于表达式)
  • ConvertUsing (Expression-based) ConvertUsing(基于表达式)
  • Ignore忽视
  • NullSubstitute空替换
  • Value transformers价值转换器
  • IncludeMembers包括成员

Not supported:不支持:

  • Condition健康)状况
  • SetMappingOrder设置映射顺序
  • UseDestinationValue使用目标值
  • MapFrom (Func-based) MapFrom(基于函数)
  • Before/AfterMap之前/之后地图
  • Custom resolvers自定义解析器
  • Custom type converters自定义类型转换器
  • ForPath路径
  • Value converters价值转换器
  • Any calculated property on your domain object您域 object 上的任何计算属性

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM