Как фильтровать вложенные объекты Entity Framework коллекции?
вот в чем проблема: Мне нужно вернуть коллекцию объектов с отфильтрованными вложенными коллекциями. Например: есть магазин с заказами, и мне нужно вернуть коллекцию с магазинами, которая включает вложенные коллекции с заказами, но без заказов от клиентов, которые помечены как удаленные.
вот что я пытаюсь сделать. Но все равно не повезло. Любые предложения приветствуются :)
public List<StoreEntity> GetStores(Func<Store, bool> storeFilter, Predicate<OrderEntity> orderFileter)
{
IQueryable<StoreEntity> storeEntities = Context.Stores
.Include(o => o.Order)
.Include(cu => cu.Orders.Select(c => c.Customer))
.Where(storeFilter)
//.Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) //just test this doesn't work
.AsQueryable();
List<StoreEntity> storeEntities = storeEntities.ToList();
//storeEntities.ForEach(s => s.Orders.ToList().RemoveAll(c=>c.Customer.Deleted==true)); // doesn't work
foreach (StoreEntity storeEntity in storeEntities)
{
storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true);
}
return storeEntities;
}
проблема в том, что фильтр не применяется. Клиенты, которые удалили флаг установите значение true stay в коллекции.
3 ответов
вы не можете сделать это прямо "аккуратно", но у вас есть несколько вариантов.
Прежде всего, вы можете явно загрузите дочернюю коллекцию после того, как вы получили магазины. Вижу применение фильтров при явной загрузке связанных объектов.
если вы не хотите совершать дополнительные поездки в базу данных, вам придется создать свой собственный запрос и спроецировать родительскую коллекцию и отфильтрованные дочерние коллекции на другой объект вручную. См. следующие вопросы для примеров:
Linq to Entities - как фильтровать дочерние сущности
LINQ Query - как сортировать и фильтровать по eager fetch
редактировать
кстати, твой первый .Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false))
попытка не работает, так как таким образом вы применяете фильтр к родительской коллекции (хранилищам), а не к вложенной коллекции (например, ко всем хранилищам, в которых нет удаленных клиентов).
Логически, фильтрация кода вложенной коллекции должна быть помещена в Include
метод. В настоящее время Include
поддерживает только Select
заявление, но лично я думаю, что пришло время для команды EF реализовать что-то вроде:
.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted)));
проблема с кодом, который у вас в настоящее время есть, это строка:
storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true);
storeEntity.Orders.ToList()
возвращает новая List<OrderEntity>
с содержанием storeEntity.Orders
. Из этого нового списка удаляются все удаленные клиенты. Однако после этого этот список нигде не используется.
однако, даже если он будет делать то, что вы хотите, это будет также удалить клиентов из базы данных, потому что ваш StoreEntity
объекты по-прежнему подключены к контексту данных!
вы очень хочу использовать фильтр, как вы впервые попробовали в комментариях Where
. Пожалуйста, прочитайте ответ Yakimych для этого.
старая тема, но я столкнулся с весьма похожей проблемой. Я много искал, и ссылка MSDN, предоставленная Якимычем, наконец, намекнула мне на решение: явно отключить ленивую загрузку, а затем сделать запросы для фильтрации свойств навигации. Затем результат будет "прикреплен" к основному запросу, который даст что-то вроде этого :
Context.Configuration.LazyLoadingEnabled = false;
var filteredOrders = Context.Orders.Where(x => x.Customer.Delete == false);
IQueryable<StoreEntity> storeEntities = Context.Stores
.Include(o => o.Order)
.Include(cu => cu.Orders.Select(c => c.Customer))
.Where(storeFilter)
.AsQueryable();