2016-07-05 28 views
5

Tło

muszę być w stanie zbudować .Include że filtry Wyników dół do rejestrów utworzonych na lub przed określoną datą. Nie znam typów obiektów na oryginalnym wyciągu LINQ i znajdę je (przez całą masę obręczy, ale to działa).dynamicznego tworzenia Dołącz z Gdzie Filtr

Mam wykres obiektów tak:

  A -> Ac 
     /\ 
    Bc <- B \ 
    / \ 
Cc <- C  D -> Dc 

Obiekty Ac, Bc, Cc, a wszystko Dc znajdują się dynamicznie (to jest deweloper nie wpisać w te relacje pisząc oryginalny LINQ komunikat). Następnie należy je dodać do wyrażenia IQueryable i zwracać wartości tylko do określonego obiektu DateTime.

Kodeks So Far

próbowałem budowania funkcji, które konstruuje lambda i porównuje dat. Do tej pory, jeśli oryginalne zapytanie to A.Include(x => x.B).Include(x => x.B.Select(y => y.C), mogę skonstruować ciąg "A.B.Bc", więc znam typy A, B i Bc oraz sposób, w jaki się one odnoszą.

private static IQueryable<T> FilterChangeTrackerToDate<T>(this IQueryable<T> query, string includeString, DateTime targetDateTime) 
{ 
    var param = Expression.Parameter(typeof(T), "x"); 

    var prop = Expression.Property(param, includeString + ".CreatedUtc"); 

    var dateConst = Expression.Constant(targetDateTime); 

    var compare = Expression.LessThanOrEqual(prop, dateConst); 

    var lambda = Expression.Lambda<Func<T, bool>>(compare, param); 

    return query.Where(lambda); 
} 

Problem jest, że powyższy kod wywala bo "A.B.Bc.CreatedUtc" nie jest poprawny sposób, aby załadować właściwość data - muszę przechodzić przez to .Select wypowiedzi.

Problem

W celu zarówno obciążenie zapisy i filtr im, muszę dynamicznie zbudować .Select wyciągnąć wartości potrzebne (które, na szczęście, są statyczne na podstawie dziedziczenia) i umieść te wartości w anonimowym typie, który można następnie przefiltrować za pomocą .Where(). Wszystko to musi być zrobione przy minimalnym poziomie generycznym, ponieważ nie mam typów kompilacji do sprawdzenia i musiałem nadużywać refleksji, aby je uruchomić.

Zasadniczo trzeba utworzyć w ten sposób:

.Select(x => new 
{ 
    Bc = x.B.Select(z => z.Bc.Select(y => y.CreatedUtc).Where(q => q > DateTime.UtcNow)), 
    A= x 
}) 

dynamicznie przy użyciu ciąg "A.B.Bc", na dowolnym poziomie zagnieżdżenia.

Resources

To gdzie ja zobaczyłem jak filtrować EF obejmują metody: LINQ To Entities Include + Where Method

Ten post mówi o dynamicznie tworząc Select, ale to jest wybór tylko wartości najwyższego poziomu i nie wydaje jak można go zbudować resztę części potrzebnych do mojego problemu: How to create LINQ Expression Tree to select an anonymous type

dynamiczne Linq

Używanie System.Linq.Dynamiczne biblioteki, starałem się uzyskać dostęp do wartości CreatedUtc off BC:

query = (IQueryable<T>) query.Select(includeString + ".CreatedUtc"); 

Gdzie includeString = "B.Bc", ale to daje mi wyjątek:

Exception thrown: 'System.Linq.Dynamic.ParseException' in System.Linq.Dynamic.dll 

Additional information: No property or field 'Bc' exists in type 'List`1' 

Odpowiedz

2

wierzę System.Linq.Dynamic jest to, czego potrzebujesz. Jest to biblioteka napisana przez ScottGu z Microsoft, a to pozwala budować LINQ kwerendy z ciągiem tak:

IQueryable nestedQuery = query.Select("B.Bc.CreatedUtc"); 

gdzie zapytanie jest IQueryable<A>.

Jest wiele widelców tej biblioteki. Możesz zacząć od here. Dokumentacja w języku zapytań to here. Również here istnieje wersja z dodatkowymi funkcjami, a here jest wersją dotnet.core.

UPD1: This biblioteka brakuje metody wydłużania SelectMany ale this trzeba. Więc z drugiej biblioteki można wykonać następujące czynności:

query.SelectMany("B").SelectMany("Bc").Select("CreatedUtc"); 
+0

Kiedy to ciąg '„B.Bc.CreatedUtc”', otrzymuję ten błąd: 'Informacje dodatkowe: Nie istnieje nieruchomości lub pole„Bc”w typie "Lista" 1 ". Wygląda na to, że nie zagląda poprawnie do zagnieżdżonych wykresów? – Max

+0

Czy możesz pokazać tutaj więcej kodu? –

+0

Zaktualizowałem mój główny wpis. – Max