Ответ 1
Закончено изменение исходного кода AutoMapper для поддержки этого сценария. Надеемся, что предлагаемое исправление будет принято, но пока вы можете увидеть подробности: -
У меня есть граф объектов, который я загружаю из базы данных, используя EF CodeFirst и AutoMapper в DTO: -
public class Foo
{
public int Id { get; set; }
public virtual ICollection<Bar> Bars { get; set; }
}
public class Bar
{
public int Id { get; set; }
public int FooId { get; set; }
public virtual Foo Foo { get; set; }
public string Name { get; set; }
public int SortOrder { get; set; }
}
public class FooDto
{
public IEnumerable<BarDto> Bars { get; set; }
}
public class BarDto
{
public string Name { get; set; }
public int SortOrder { get; set; }
}
Мои сопоставления выглядят так: -
mapper.CreateMap<Foo, FooDto>();
mapper.CreateMap<Bar, BarDto>();
До сих пор так хорошо. Я могу захватить сущности из моего контекста и выполнить проект в DTO: -
var foos = context.Foos.Project().To<FooDto>();
То, что я не могу сделать с этим подходом, однако, сортирует Bars
по их SortOrder
внутри IQueryable.
Если я попробую: -
mapper.CreateMap<Foo, FooDto>()
.ForMember(
x => x.Bars
opt => opt.MapFrom(src => src.Bars.OrderBy(x => x.SortOrder)));
mapper.CreateMap<Bar, BarDto>();
var foos = context.Foos.Project().To<FooDto>();
Я получаю исключение: -
System.InvalidOperationException: Sequence contains no elements
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
at AutoMapper.MappingEngine.CreateMapExpression(Type typeIn, Type typeOut)
...
Похоже, это связано с https://github.com/AutoMapper/AutoMapper/issues/159 - хотя я уже использую сложный тип для дочерней коллекции. Я думаю, что CreateMapExpression не поддерживает OrderBy в дочерних коллекциях?
Если я не использую .Project(). Для() я могу легко сортировать дочернюю коллекцию: -
var model = context.Foos.Select(x => new FooDto()
{
Bars = x.Bars.OrderBy(y => y.SortOrder)
});
но затем мне нужно повторить отображение везде, где я хочу его использовать, победив цель использования AutoMapper.
Любопытно: -
1) Я могу выполнять другие (более сложные?) операции над дочерней коллекцией и сглаживать их в моем родительском DTO без проблем: -
mapper.CreateMap<Foo, FooDto>()
.ForMember(
x => x.AllBarsHaveAName,
opt => opt.MapFrom(src =>
src.Bars.All(x => x.Name != null)));
2) Я могу Mapper.Map<FooDto>(foo);
в памяти просто отлично, и он не сортирует бары без проблем.
Можно сортировать дочернюю коллекцию на уровне IQueryable при использовании .Project(). To()?
Закончено изменение исходного кода AutoMapper для поддержки этого сценария. Надеемся, что предлагаемое исправление будет принято, но пока вы можете увидеть подробности: -
Интересно, является ли сортировка баров внутри Queryable во время сопоставления лучшим местом для этого? Не помещал ли этот вид на карту, чтобы сортировать ее в ненадлежащее время?
Например, что, если вы просто хотели узнать, содержит ли коллекция Bars 1 элемент? призвание
FooDto.Bars.Any()
все равно приведет к сортировке в базе данных.
Возможно, было бы лучше иметь другое свойство в FooDTO (игнорируется в сопоставлении), которое выглядит так:
public IEnumerable<BarDto> SortedBars
{
get
{
if (Bars == null)
return null;
return Bars.OrderBy(x => x.SortOrder).ToList();
}
}