Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

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

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

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

var parent = context.Parents.First(...);
var entry = context.Entry(parent);
entry.Collection(e => e.Children)
     .Query()
     .OrderBy(c => c.SortOrder)
     .Load();

Ответ 2

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

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

Объяснение

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

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

Первый фрагмент

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

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

Второй фрагмент

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

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

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

  • Подумайте о вещах в db, которые устанавливаются до тех пор, пока не будет достигнут абсолютный последний момент.

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

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

var model = groups.First().P;

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

var model = groups.FirstOrDefault()?.P;