Entity Framework загружает дочернюю коллекцию с порядком сортировки - PullRequest
30 голосов
/ 30 марта 2012

У меня есть две таблицы: родительская и дочерняя.Дочерняя таблица имеет сортировщик столбцов (числовое значение).Из-за отсутствия поддержки EF для сохранения IList, включающего порядок сортировки без раскрытия сортировщика (см .: Entity Framework, сохраняющий порядок сортировки дочерней коллекции ), мой дочерний класс также имеет свойство SortOrder, поэтомусохранить детей с порядком сортировки.

В отличие от автора указанного вопроса, я стараюсь загружать детей всегда отсортированными.Поэтому, если я загружу родительский экземпляр, я ожидаю, что дочерняя коллекция отсортирована по порядку сортировки.Как я могу добиться такого поведения с помощью API Code First Fluent и POCO?

Подсказка: нельзя вызывать .Sort (...) для дочерней коллекции.

Ответы [ 2 ]

38 голосов
/ 30 марта 2012

Вы не можете достичь этого напрямую, потому что ни энергичная, ни ленивая загрузка в EF не поддерживает упорядочивание или фильтрацию.

Ваши варианты:

  • Сортировка данных в приложении после загрузки их из базы данных
  • Выполнить отдельный запрос для загрузки дочерних записей. Как только вы используете отдельный запрос, вы можете использовать OrderBy

Второй вариант можно использовать с явной загрузкой:

var parent = context.Parents.First(...);
var entry = context.Entry(parent);
entry.Collection(e => e.Children)
     .Query()
     .OrderBy(c => c.SortOrder)
     .Load();
27 голосов
/ 20 октября 2014

Вы можете сделать это эффективно в одном запросе, грамматика просто неловкая:

var groups = await db.Parents
    .Where(p => p.Id == id)
    .Select(p => new
        {
            P = p,
            C = p.Children.OrderBy(c => c.SortIndex)
        })
    .ToArrayAsync();

// Query/db interaction is over, now grab what we wanted from what was fetched

var model = groups
    .Select(g => g.P)
    .FirstOrDefault();

Объяснение

асинхронная заметка

Iслучайно здесь использовались расширения async, которые вы, вероятно, должны использовать, но вы можете избавиться от await / async, если вам нужен синхронный запрос без ущерба для эффективной дочерней сортировки.

Первый блок

По умолчанию все объекты EF, извлеченные из БД, отслеживаются.Кроме того, EF-эквивалент SQL Select разработан вокруг анонимных объектов, которые вы видите выше.Когда создается анонимный объект, оба объекта, назначенные P и C, отслеживаются, это означает, что их отношения отмечаются, и их состояние поддерживается EF Change Tracker.Поскольку C - это список дочерних элементов в P, даже если вы не просили, чтобы они были явно связаны в вашем анонимном объекте, EF в любом случае загружает их как эту дочернюю коллекцию, из-за взаимосвязион видит в схеме.

Чтобы узнать больше, вы можете разбить вышеперечисленное на 2 отдельных запроса, загружая только родительский объект, а затем только дочерний список, в совершенно разных вызовах Db.EF Change Tracker заметит и загрузит дочерние элементы в родительский объект для вас.

Второй кусок

Мы обманули EF в возвращении упорядоченных дочерних объектов.Теперь мы берем только родительский объект - его дочерние элементы все равно будут присоединены в том порядке, в котором мы хотели.

Нули и таблицы как наборы

Есть неловкий двухэтапный шагздесь в основном для лучших практик вокруг нулей;он должен делать 2 вещи:

  • Думайте о вещах в БД как о наборах до тех пор, пока не станет возможным абсолютный последний момент.

  • Избегайте нулевых исключений.

Другими словами, последний кусок мог бы быть:

var model = groups.First().P;

Но если объект отсутствует в БД, он взорвется сисключение нулевой ссылки. C # 6 представит другую альтернативу - оператор слияния нулевых свойств - так что в будущем вы можете заменить последний кусок на:

var model = groups.FirstOrDefault()?.P;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...