Я использую AutoMapper .ProjectTo<OrderDto>()
, чтобы сопоставить некоторые Order
с OrderDto
.
Исходный ордер - довольно большой объект с около 30 свойствами и 15 коллекциями.
Для моего OrderDto у меня есть свойство DisplayStatus
с некоторыми пользовательскими логинами c на основе 4 свойств в исходном Order. Мне не нужны эти свойства в моем последнем OrderDto, мне просто нужно, чтобы они делали что-то вроде GetDisplayStatus()
.
Я пробовал несколько способов сделать это, и ни один из них не кажется мне удовлетворительным, так что мое предположение Я должен делать что-то не так. Там должен быть лучший способ.
Сначала я попытался использовать пользовательский преобразователь значений , но вы не можете использовать их внутри проекции IQueryable, поскольку они не могут быть переведены в Linq (если я правильно понял).
Затем я попытался сделать что-то вроде этого
.ForMember(target => target.DisplayStatus, option => option.MapFrom(source => GetDisplayStatus(source))
Проблема в том, что Entity Framework считает это «черным ящиком» и не имеет возможности узнать, что мне нужно и что я нет. Поэтому весь исходный объект передается в функцию. В результате в последнем запросе SQL применяется Select
ко всем столбцам, начиная с Order
, что приводит к увеличению размера запроса из-за большого количества ненужных данных, и производительность падает с большим отрывом.
В конце концов, текущий способ сделать это в нашей кодовой базе выглядит примерно так:
.ForMember(target => target.DisplayStatus, option => option.MapFrom(source =>
GetDisplayStatus(new TempOrder{
someProperty = source.someProperty
anotherPropery = source.anotherProperty
}))
Этим способом я могу точно определить, какие свойства исходного Ордена я хочу чтобы перейти к моей GetDisplayStatus()
функции и окончательный SQL Запрос остается чистым.
Недостатком является то, что код может быстро стать довольно уродливым, когда вещи, которые вы хотите передать своей функции, требуют некоторой работы сами.
.ForMember(target => target.DisplayStatus, option => option.MapFrom(source =>
GetDisplayStatus(source.OrderProducts.Where(//a lot of work here too//).Select(op =>
new TempOrderProduct
{
ProductTypeId = op.ProductTypeId,
HasFiles = op.OrderFiles.Any(),
VisitDate = op.VisitDate
}), source.OrderStatus)))
Опять же, это не правильно. Есть лучший способ сделать это ?
Спасибо.
Редактировать
Здесь тот же запрос без AutoMapper, как и в комментариях
public static IQueryable<OrderDTO> MapOrderDTO(this IQueryable<Orders> orders)
{
return orders
.Select(order => new OrderDTO
{
OrderID = order.OrderId,
OrderCreationDate = order.OrderCreationDate,
OrderStatus = order.OrderStatus,
DisplayStatus = GetDisplayStatus(order.OrderProducts
.Where(//a lot of work//)
.Select(op => new TempOrderProduct
{ ProductTypeId = op.ProductTypeId,
HasFiles = op.OrderFiles.Any(),
VisitDate = op.VisitDate }),
order.OrderStatus)
})
});
}