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

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

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

Подсказка: это не вариант звонить .Род.(..) о детской коллекции.

2 ответов


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

ваши возможности:

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

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

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

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

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 извлечены из БД "отслеживаются"."Кроме того, EF эквивалентен SQL Select предназначен вокруг анонимных объектов, которые вы видите, что мы выбираем выше. При создании анонимного объекта Объекты, назначенные P и C оба отслеживаются, то есть их отношения отмечаются, и их состояние поддерживается трекером изменений EF. С C список детей в P, даже если вы не просили их явно быть связанными в вашем анонимном объекте,нагрузки EF их как эту детскую коллекцию во всяком случае, из-за отношения он видит в схеме.

чтобы узнать больше, вы можете разбить выше на 2 отдельных запроса, загрузив только родительский объект, а затем только дочерний список, в совершенно разных вызовах БД. Трекер изменений EF заметит и загрузит детей в родительский объект для вас.

второй кусок

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

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

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

  • подумайте о вещах в БД как о множествах до абсолютного последнего момента.

  • избегайте исключений null.

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

var model = groups.First().P;

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

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