Вы можете запросить требуемые объекты с помощью
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 имеет эту функцию fixup , которая заботится о настройке всех ассоциаций между объектами, которые реализованы в контексте. Это означает, что для каждого Bus
теперь загружаются только его бодрые пассажиры.
Когда вы получаете сбор автобусов на ToList
, у вас есть автобусы с нужными вами пассажирами, и вы можете сопоставить их с помощью AutoMapper .
Это работает только при отключенной ленивой загрузке. В противном случае EF будет ленить нагрузка всех пассажиров для каждой шины, когда к ним обращаются пассажиры во время конвертации в DTO.
Существует два способа отключения ленивой загрузки. Отключение LazyLoadingEnabled
приведет к повторной активации ленивой загрузки при ее повторном включении. Отключение ProxyCreationEnabled
создаст сущности, которые не способны к ленивой загрузке сами , поэтому они не начнут ленивую загрузку после того, как ProxyCreationEnabled
снова будет активирован. Это может быть лучшим выбором, когда контекст живет дольше, чем только этот единственный запрос.
Но ... многие-ко-многим
Как уже говорилось, эта работа зависит от отношения исправить. Однако, как объяснено здесь Slauma , исправление отношения не работает со многими ассоциациями. Если Bus
- Passenger
много-ко-многим, единственное, что вы можете сделать, это исправить:
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
Начиная с версии 2.0.0, EF-core имеет фильтры запросов уровня модели . Хотя это отличное дополнение к его функциям, пока ограничение заключается в том, что оно не может быть применено к свойствам навигации, а только к корневой сущности запроса. Надеемся, что в более поздней версии эти фильтры получат более широкое использование.