2013-02-14 2 views
14

У меня есть объект граф, который я загружаю из базы данных с помощью EF CodeFirst и AutoMapper в DTOS: -.AutoMapper Project() К() и сортировки коллекции детской

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()?

ответ

11

Законченных изменения исходного кода AutoMapper для поддержки этого сценария.Буду надеяться, что предлагаемое исправление будет принято, но в то же время вы можете увидеть подробности по адресу: -

https://github.com/AutoMapper/AutoMapper/pull/327

+1

Запрос на перенос был принят, и изменение теперь в automapper 3. –

+0

Я использую AutoMapper 3.3.1, он позволяет orderby в конфигурации Mapper, но на самом деле он не упорядочивает. данные не сортируются, и sql-профайлер не показывает порядок в сгенерированном sql. Что мне не хватает? – mendel

+0

Возможно, ошибка появилась с версии 3.0 или может быть проблемой с вашей конфигурацией. Опубликовать [MCVE] (http://stackoverflow.com/help/mcve) как новый вопрос, ссылку на него здесь, и я посмотрю? –

0

Мне интересно, если сортировка баров внутри Queryable во время отображения является лучшим местом для этого? Не помещал ли этот вид на карту, чтобы сортировать ее в ненадлежащее время?

Например, если вам просто нужно знать, содержит ли коллекция Bars 1 элемент? Вызов FooDto.Bars.Any() все равно приведет к сортировке в базе данных.

Возможно, было бы лучше иметь другое свойство в FooDTO (проигнорировано в отображении), который выглядит следующим образом:

public IEnumerable<BarDto> SortedBars 
    { 
     get 
     { 
      if (Bars == null) 
       return null; 

      return Bars.OrderBy(x => x.SortOrder).ToList(); 
     } 
    } 
+0

Я думаю, что вы могли бы потенциально использовать метод «AfterMap» на конфигурацию отображения материала в AutoMapper, чтобы сделать вашу сортировку ? –

+0

Колин: Я вряд ли вытащу весь DTO, чтобы увидеть, если FooDto.Bars.Any() - это конкретный запрос для определенного вида. –

+0

Richard B: Я посмотрел AfterMap, и он выполнит эту работу (как и свойство «SortedBars» Колина) после моды, но с профилированием я бы предпочел, чтобы сортировка имела место в базе данных, как это происходит, когда я это делаю .Select (x => new FooDto ...) –

Смежные вопросы