我有一个简单的任务:只需将一个类映射到另一个类。对于某些字段,我有复杂的逻辑,取决于 2 个或更多字段,因此,我尝试使用ConvertUsing
(https://docs.automapper.org/en/stable/Custom-type-converters.html)
我使用 AutoMapper 10.0.0
我的代码是:
源码类:
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; }
}
Run Code Online (Sandbox Code Playgroud)
DTO类:
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; }
}
Run Code Online (Sandbox Code Playgroud)
和自动映射器类:
public class AutoMapperEfDeviceManagement : AutoMapper.Profile
{
public AutoMapperEfDeviceManagement()
{
CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>().ConvertUsing<DeviceChangeStatusConverter>();
}
}
Run Code Online (Sandbox Code Playgroud)
其中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;
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我尝试绘制它时:
var list = _context.DeviceStatusHistory
.Where(a => ((int)a.NewStatus < 100) && a.DateChange.Date == date.Date)
.ProjectTo<DeviceChangeStatusDto>(_mapperConfig)
.ToList();
Run Code Online (Sandbox Code Playgroud)
哪里_mapperConfig
:
_mapperConfig = new MapperConfiguration(cfg =>
{
cfg.AddProfile<AutoMapperEfDeviceManagement>();
});
Run Code Online (Sandbox Code Playgroud)
它的映射看起来很简单:
CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>();
Run Code Online (Sandbox Code Playgroud)
因此,仅映射相同的属性,不会调用转换器(调试器也这么说)。怎么了?
添加:
方法如下:
CreateMap<DeviceStatusHistory, DeviceChangeStatusDto>()
.ConvertUsing((source, destination) =>
{
destination.CarrierName = source.Device.CarrierId.HasValue ? source.Device.Carrier.Name : null;
Run Code Online (Sandbox Code Playgroud)
也不起作用
长话短说
\n这不是一个错误,而是一个已知的限制。基本上 AutoMapper 无法将某些自定义方法转换为 SQL(或将其转换为允许 ORM 将其转换为 SQL 的形式),因此它无法在ProjectTo
.
更多细节:
\n从文档中:
\n\n\n会
\n.ProjectTo<OrderLineDTO>()
告诉AutoMapper
\xe2\x80\x99s 映射引擎向 发出一个select
子句,该IQueryable
子句将通知实体框架它只需要查询Name
表的列Item
,就像您手动将您投影IQueryable
到OrderLineDTO
with aSelect
子句一样。
从自定义类型转换部分:
\n\n\n有时,您需要完全替换从源类型到目标类型的类型转换。在正常的运行时映射中,这是通过该
\nConvertUsing
方法完成的。要在 LINQ 投影中执行模拟,请使用以下ConvertUsing
方法:cfg.CreateProjection<Source, Dest>().ConvertUsing(src => new Dest { Value = 10 });
\n基于表达式的重载比基于重载的ConvertUsing
限制稍多一些,因为只有在和底层 LINQ 提供程序中允许的内容才会起作用。Func
ConvertUsing
Expression
和支持的映射选项:
\n\n\n并非所有映射选项都受支持,因为生成的表达式必须由 LINQ 提供程序解释。AutoMapper 仅支持 LINQ 提供程序支持的内容:
\n
\n\n\n
\n- MapFrom(基于表达式)
\n- ConvertUsing(基于表达式)
\n- 忽略
\n- 空替代
\n- 价值转换器
\n- 包括成员
\n
\n\n不支持:
\n
\n\n\n
\n- 健康)状况
\n- 设置映射顺序
\n- 使用目标值
\n- MapFrom(基于函数)
\n- 之前/之后地图
\n- 自定义解析器
\n- 自定义类型转换器
\n- 路径
\n- 价值转换器
\n- 域对象上的任何计算属性
\n
归档时间: |
|
查看次数: |
1111 次 |
最近记录: |