EF: Включить с предложением где

Как следует из названия, я ищу способ сделать предложение where в сочетании с include.

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

Позволять'скажем, у меня есть объект Bus и объект People (в Bus есть навигационная опора Collection of People). В моем запросе мне нужно выбрать все автобусы только с теми пассажирами, которые не спят. Это упрощенный фиктивный пример

В текущем коде:

var busses = Context.Busses.Where(b=>b.IsDriving == true);
foreach(var bus in busses)
{
   var passengers = Context.People.Where(p=>p.BusId == bus.Id && p.Awake == true);
   foreach(var person in passengers)
   {
       bus.Passengers.Add(person);
   }
}

После этого кода контекст удаляется, и в вызывающем методе результирующие объекты шины отображаются в класс DTO (100% копия объекта).

Этот код вызывает несколько обращений к БД, которая является No-Go, поэтому я нашел это решениеПО MSDN Блоги

Это отлично работало при отладке результата, но когда сущности сопоставляются с DTO (с помощью AutoMapper), я получаю исключение, что Context / Connection был закрыт и что объект может 'не быть загруженным. (Контекст всегда закрытизменить это :()

Поэтому мне нужно убедиться, что выбранные пассажиры уже загружены (свойство IsLoaded для навигации также имеет значение False). Если я осматриваю коллекцию Пассажиров, Граф также выбрасывает Исключение, но в Коллекции Пассажиров также есть коллекция под названием «обернутые связанные объекты » которые содержат мои отфильтрованные объекты.

Есть ли способ загрузить эти обернутые связанные сущности во всю коллекцию? (Я могу't изменить конфигурацию отображения автомпера, потому что она используется во всем приложении).

Есть ли другой способ получить активных пассажиров?

Любая подсказка приветствуется ...

редактировать

Ответ Герта Арнольдане работает, потому что данные незагружен с нетерпением. Но когда я упрощаю это и удаляю, куда это загружено. Это действительно странно, так как в обоих случаях команда execute sql возвращает всех пассажиров. Таким образом, должна быть проблема, когда результаты возвращаются в сущность.

Context.Configuration.LazyLoadingEnabled = false;
var buses = Context.Busses.Where(b => b.IsDriving)
        .Select(b => new 
                     { 
                         b,
                         Passengers = b.Passengers
                     })
        .ToList()
        .Select(x => x.b)
        .ToList();
Edit2

После большой борьбы ответ Герт Арнольд работы! Как предположил Герт Арнольд, вам нужно отключить Lazy Loading и держать его выключенным. Это потребует некоторых дополнительных изменений в приложении, так как предыдущий разработчик любил Lazy Loading -_-

 Travis J28 мая 2013 г., 20:49
Можете ли вы также показать нам, как будет выглядеть пример соответствующих частей реализации класса для Bus, People и Passengers (таких как внешние ключи и свойства Navigation)?
 Beejee28 мая 2013 г., 22:04
Пассажиры - это навигационная опора
 Beejee28 мая 2013 г., 20:37
это просто пример, написанный в stackoveflow без intellisense: p Исправлено
 Ellesedil30 апр. 2014 г., 23:20
Я несколько удивлен, что этот вопрос почти не уделяется внимания, учитывая, насколько мне было трудно его найти и какЭто отличный способ ограничить объем данных, для которых EF запрашивает базу данных. Разве люди не видели запросы, которые EF создает для базы данных?
 Suamere31 авг. 2018 г., 21:57
@Ellesedil Ваше мнение верно, но те "долго" Запросы EF только длинные для человека. Они на самом деле очень эффективны. Вы'Было бы трудно написать запрос с более быстрым планом выполнения, чем тот, который EF генерирует на регулярной основе.

Ответы на вопрос(2)

Решение Вопроса

Вы можете запросить необходимые объекты по

Context.Configuration.LazyLoadingEnabled = false;
// Or: Context.Configuration.ProxyCreationEnabled = false;
var buses = Context.Busses.Where(b => b.IsDriving)
            .Select(b => new 
                         { 
                             b,
                             Passengers = b.Passengers
                                           .Where(p => p.Awake)
                         })
            .AsEnumerable()
            .Select(x => x.b)
            .ToList();

Здесь происходит то, что вы сначала выбираете ведущие автобусы и пробуждаете пассажиров из базы данных. Затем,AsEnumerable() переключается с LINQ на Entities на LINQ на объекты, что означает, что автобусы и пассажиры будут материализованы и затем обработаны в памяти. Это важно, потому что без этого EF только материализует окончательный прогноз,Select(x => x.b)а не пассажиры.

Теперь EF имеет эту функциюисправление отношений это заботится об установке всех ассоциаций между объектами, которые материализуются в контексте. Это означает, что для каждогоBus теперь загружены только его активные пассажиры.

Когда вы получаете коллекцию автобусов поToList у вас есть автобусы с нужными пассажирами, и вы можете сопоставить их с AutoMapper.

Это работает только тогда, когда отложенная загрузка отключена. Иначе EF будет лениво грузитьвсе пассажиры для каждого автобуса, когда к пассажирам обращаются во время преобразования в DTO.

Есть два способа отключить отложенную загрузку. ОтключениеLazyLoadingEnabled возобновит ленивую загрузку, когда она снова будет включена. ОтключениеProxyCreationEnabled создаст объекты, которые не 'т способен на ленивую загрузкусамих себятак они победилит ленивая загрузка послеProxyCreationEnabled снова включен Это может быть лучшим выбором, когда контекст живет дольше, чем этот единственный запрос.

Но ... многие ко многим

Как уже говорилось, этот обходной путь основан на исправлении отношений. Однако, как объяснилиВот отSlauma, отношения не исправляютсяработать со многими ко многим ассоциациям. Если -BusPassenger это много ко многим, единственное, что вы можете сделать, это исправить это самостоятельно:

Context.Configuration.LazyLoadingEnabled = false;
// Or: Context.Configuration.ProxyCreationEnabled = false;
var bTemp = Context.Busses.Where(b => b.IsDriving)
            .Select(b => new 
                         { 
                             b,
                             Passengers = b.Passengers
                                           .Where(p => p.Awake)
                         })
            .ToList();
foreach(x in bTemp)
{
    x.b.Pasengers = x.Passengers;
}
var busses = bTemp.Select(x => x.b).ToList();

... и все это становится еще менее привлекательным.

Сторонние инструменты

Есть библиотека,EntityFramework.DynamicFilters это делает это намного проще. Это позволяет вам определять глобальные фильтры для сущностей, которые впоследствии будут применяться каждый раз, когда сущность запрашивается. В вашем случае это может выглядеть так:

modelBuilder.Filter("Awake", (Person p) => p.Awake, true);

Теперь, если вы делаете ...

Context.Busses.Where(b => b.IsDriving)
       .Include(b => b.People)

...вы'Вы увидите, что фильтр применяется к включенной коллекции.

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

Существует аналогичная библиотека от производителя AutoMapper:EntityFramework.Filters

Ядро Entity Framework

Начиная с версии 2.0.0, EF-ядро имеетглобальные фильтры запросов, Несмотря на то, что это отличное дополнение к его функциям, пока ограничение заключается в том, что фильтр можетt содержит ссылки на свойства навигации, только на корневую сущность запроса. Надеемся, что в более поздней версии эти фильтры получат более широкое использование.

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

 xr280xr17 нояб. 2017 г., 01:03
Согласно моему отсутствующему комментарию о EntityFrameworkDynamicFilters, к сожалению, нет возможности для DB First:github.com/zzzprojects/EntityFramework.DynamicFilters/issues/12

отказ: Ям владелец проектаEntity Framework Plus

Функция EF + Query IncludeFilter позволяет фильтровать связанные объекты.

var buses = Context.Busses
                   .Where(b => b.IsDriving)
                   .IncludeFilter(x => x.Passengers.Where(p => p.Awake))
                   .ToList();

Wiki:EF + Query IncludeFilter

 Jonathan Magnan29 сент. 2018 г., 03:24
В настоящее время вы не можете выключить его.
 AGuyCalledGerald08 мая 2019 г., 16:14
не работает ядро платформы сущностей в настоящее время?
 jDave198428 сент. 2018 г., 22:10
Это прекрасно работает. Как вы отключите IncludeFilter?

Ваш ответ на вопрос