Entity Framework, MVC 3, OrderBy в LINQ To Entities - PullRequest
4 голосов
/ 24 августа 2011

У меня следующий запрос:

model.Page = db.Pages
    .Where(p => p.PageId == Id)
    .Include(p => p.Series
                   .Select(c => c.Comics
                                 .Select(col => col.Collection)))
    .SingleOrDefault();

Это прекрасно работает, хотя теперь мне нужно упорядочить комиксы по свойству с именем ReadingOrder.

Я пробовал:

model.Page = db.Pages
    .Where(p => p.PageId == Id)
    .Include(p => p.Series.Select(c => c.Comics.OrderBy(o => o.ReadingOrder)
                          .Select(col => col.Collection)))
    .SingleOrDefault();

Но это приводит к следующей ошибке:

Выражение «Включить путь» должно ссылаться на свойство навигации, определенное для типа.Используйте пунктирные пути для ссылочных свойств навигации и оператор Select для свойств навигации коллекции.Имя параметра: путь

Есть идеи, что означает эта ошибка?

Заранее спасибо

РЕДАКТИРОВАТЬ:

Myмодели:

public class Page
{
    public int PageId { get; set; }
    public string Title { get; set; }
    public ICollection<Series> Series { get; set; }
}

public class Series
{
    public int SeriesId { get; set; }
    public int PageId { get; set; }
    public string Title { get; set; }
    public Page Page { get; set; }
    public ICollection<Comic> Comics { get; set; }
}

public class Comic
{
    public int ComicId { get; set; }
    public string Title { get; set; }
    public int ReadingOrder { get; set; }
    public string Subtitle { get; set; }
    public int CollectionId { get; set; }
    public Collection Collection { get; set; }

}

public class Collection
{
    public int CollectionId { get; set; }
    public string Title { get; set; }
    public ICollection<Comic> Comics { get; set; }
}

Ответы [ 2 ]

10 голосов
/ 25 августа 2011

Исключение " ... Выражение пути включения должно ссылаться на свойство навигации ... ", в основном жалуется, что c.Comics.OrderBy не является свойством навигации. (Думаю, это законная жалоба.)

На самом деле EF не поддерживает применение сортировки (а также фильтрации) в выражениях загрузки (Include).

Итак, что вы можете сделать?

Вариант 1:

Сортировка в памяти после загрузки объекта:

model.Page = db.Pages
    .Where(p => p.PageId == Id)
    .Include(p => p.Series.Select(c => c.Comics
                          .Select(col => col.Collection)))
    .SingleOrDefault();

if (model.Page != null)
{
    foreach (var series in model.Page.Series)
        series.Comics = series.Comics.OrderBy(c => c.ReadingOrder).ToList();
}

Ужасно, но поскольку вы загружаете, по-видимому, только один объект Page по идентификатору, возможно, он быстрее (LINQ to Objects в памяти), чем следующие параметры (если коллекции Series и Comics не слишком длинные).

Вариант 2:

Разбейте запрос на части, которые смешивают энергичную и явную загрузку:

model.Page = db.Pages
    .Where(p => p.PageId == Id)
    .Include(p => p.Series) // only Series collection is included
    .SingleOrDefault();

if (model.Page != null)
{
    foreach (var series in model.Page.Series)
        db.Entry(series).Collection(s => s.Comics).Query()
          .Include(c => c.Collection)
          .OrderBy(c => c.ReadingOrder)
          .Load(); // one new DB query for each series in loop
}

Вариант 3:

Прогноз

Здесь и здесь - это, кстати, что-то об опасностях сложных Include цепочек с несколькими навигационными свойствами. Он может загружать огромное количество дублированных данных. Include гарантирует, что у вас есть только один обход БД, но, возможно, за счет гораздо большего количества передаваемых данных. Явная загрузка имеет несколько циклов обработки, но с общим объемом данных, возможно, меньшим.

(Я знаю, я дал вам эту цепочку Включить ... Выбрать ... Выбрать ... Выбрать ..., но как я узнал, что вы отнесетесь ко мне серьезно :). Ну, в зависимости от размера ваших вложенных коллекций, это все равно может быть лучшим вариантом.)

0 голосов
/ 24 августа 2011

С макушки головы, не проверено:

model.Page = db.Pages
               .Where(p => p.PageId == Id)
               .Include(p => p.Series
                              .Select(c => c.Comics
                                            .Select(col => col.Collection)
                                            .OrderBy(o => o.ReadingOrder)))
               .SingleOrDefault();
...