2011-08-16 14 views
19

Oto problem: Muszę zwrócić kolekcję obiektów z przefiltrowanymi zbiorami zagnieżdżonymi. E.g: istnieje sklep z zamówieniami i muszę zwrócić kolekcję ze sklepami zawierającą kolekcje zagnieżdżone z zamówieniami, ale bez zamówień od klientów oznaczonych jako usunięte.Jak filtrować zagnieżdżone obiekty Entity Framework?

Oto, co próbuję zrobić. Ale wciąż nie ma szczęścia. Wszelkie sugestie są odpowiednie :)

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; 
} 

Problem polega na tym, że filtr nie jest stosowany. Klienci, którzy usunęli flagę ustawioną jako prawdziwa, pozostają w kolekcji.

+0

Co to jest problem? Czy to nie kompiluje? Czy rzuci wyjątek środowiska wykonawczego?Czy działa, ale zwraca nieprawidłowe dane? –

+0

wyjaśniłem trochę więcej. dzięki. –

+1

Skończyło się na tym pakiecie nuget: 'Z.EntityFramework.Plus.QueryIncludeFilter.EF6' Dokumentacja tutaj: https://github.com/zzzprojects/EntityFramework-Plus/wiki/EF-Query-IncludeFilter-%7C-Entity- Framework-Include-Entity-Entity-using-Where-Filter –

Odpowiedz

26

Nie możesz tego zrobić bezpośrednio w "czysty" sposób, ale masz kilka opcji.
Przede wszystkim możesz jawnie załadować kolekcję podrzędną po pobraniu sklepów. Zobacz sekcję Applying filters when explicitly loading related entities.

Jeśli nie chcesz wykonywać dodatkowych podróży do bazy danych, musisz utworzyć własne zapytanie i ręcznie wyświetlić kolekcję nadrzędną i przefiltrowane kolekcje podrzędne na innym obiekcie. Zobacz następujące pytania przykładów:
Linq To Entities - how to filter on child entities
LINQ Query - how sort and filter on eager fetch

Edycja

Nawiasem mówiąc, pierwszym .Where(rcu=>rcu.Orders.Select(cu=>cu.Customer.Deleted==false)) próba nie działa ponieważ ten sposób jest zastosowanie filtra do swojej kolekcji nadrzędnej (sklepów) zamiast zagnieżdżonej kolekcji (np. wszystkie sklepy, które nie mają usuniętych klientów).
Logicznie, kod filtrujący zagnieżdżoną kolekcję należy umieścić w metodzie Include. Obecnie Include obsługuje tylko Select oświadczenie, ale osobiście myślę, że nadszedł czas na zespół EF zaimplementować coś takiego:

.Include(cu => cu.Orders.Select(c => c.Customers.Where(cust => !cust.IsDeleted))); 
+0

Tak, zgadzam się. (Wiem, że to coś nie działa, ale wciąż chciałem to wypróbować, kto wie, może ta funkcja została ukryta i byłbym mile zaskoczony) i tak, ten rodzaj Include byłoby miło mieć. Zdecydowałem się na niestandardową projekcję ... naprawdę nie lubię tej metody, ponieważ musiałem przypisać wiele niemych wartości, takich jak (ID = r.ID, Name = r.Name ... i tak dalej). Ale przynajmniej działa :) Thx –

+3

Zgadzam się, że zespół EF powinien wdrożyć filtrowane Uwzględnij. Głosuj na to [tutaj] (https://entityframework.codeplex.com/workitem/47)! – Chris

+0

Co jeśli mam rodzajowe metodę zwaną 'GetWithInclude()' ' publicznego IQueryable GetWithInclude (params Expression > [] includeProperties) { powrót includeProperties.Aggregate >, IQueryable > (DbSet, (current, includeProperty) => current.Include (includeProperty)); } ' Jednak nie mam kolekcji i potrzebuję filtra z projekcji. Innymi słowy, mam własność, która musi coś równać. – Vyache

2

problem z kodem, które aktualnie są to ta linia:

storeEntity.Orders.ToList().RemoveAll(r=>r.Customer.Deleted==true); 

storeEntity.Orders.ToList() zwraca nowyz zawartością storeEntity.Orders. Z tej nowej listy usuniesz wszystkich usuniętych klientów. Jednak ta lista nie jest później używana.

Jednakże, nawet jeśli zrobiłoby to, co chcesz, to również usunie tych klientów z bazy danych, ponieważ twoje obiekty StoreEntity są nadal połączone z kontekstem danych!

Naprawdę chcesz użyć filtra, tak jak po raz pierwszy próbowałeś w komentowanym Where. Zobacz odpowiedź Yakimycha na pomoc.

-5

Stary temat, ale wpadłem na dość podobny problem. Dużo przeszukałem, a link MSDN dostarczony przez Yakimycha w końcu podpowiedział mi rozwiązanie: wyraźnie wyłącza leniwe ładowanie, a następnie robi zapytania, aby filtrować właściwości nawigacji. Wynik zostanie następnie "dołączony" do głównej kwerendy, która dałaby coś takiego:

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

Co to jest storeFilter? –