Sfondo
ho bisogno di essere in grado di costruire un .include che filtra i risultati fino al record creati durante o prima di una data specifica. Non conoscerò i tipi di oggetti nell'istruzione LINQ originale e li troverò (attraverso un sacco di cerchi, ma funziona).creare dinamicamente Includere con Dove Filtro
Ho un grafo di oggetti come questo:
A -> Ac
/\
Bc <- B \
/ \
Cc <- C D -> Dc
oggetti Ac
, Bc
, Cc
e Dc
si trovano tutti in modo dinamico (cioè, uno sviluppatore non digitare queste relazioni quando si scrive il LINQ originale dichiarazione). Questi devono quindi essere aggiunti a un'espressione IQueryable e restituiscono solo i valori fino a un DateTime specifico.
Il Codice So Far
ho provato la costruzione di una funzione che costruisce un lambda e mette a confronto le date. Finora, se la query originale è A.Include(x => x.B).Include(x => x.B.Select(y => y.C)
, posso creare la stringa "A.B.Bc"
, quindi conosco i tipi di A, B e Bc e il loro modo di rapportarsi.
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);
}
Il problema è che il codice di cui sopra si blocca a causa "A.B.Bc.CreatedUtc"
non è il modo corretto di caricare la proprietà data - ho bisogno di attraversare questo attraverso .Select
dichiarazioni.
Il problema
Per entrambi carico gli atti e filtro loro, devono costruire dinamicamente un .Select
per staccare i valori ho bisogno (che, fortunatamente, sono statica su eredità) e inserire quei valori in un tipo anonimo, che può essere filtrato con un .Where()
. Tutto ciò deve essere fatto con generici minimi, in quanto non ho tipi di compilazione in fase di validazione e dovrei abusare della riflessione per farli funzionare.
In sostanza, ho bisogno di creare questa:
.Select(x => new
{
Bc = x.B.Select(z => z.Bc.Select(y => y.CreatedUtc).Where(q => q > DateTime.UtcNow)),
A= x
})
in modo dinamico, utilizzando la stringa "A.B.Bc", per qualsiasi livello di nidificazione.
Risorse
Questo è dove ho visto come filtrare un EF includono metodo: LINQ To Entities Include + Where Method
Questo post parla di creazione dinamica di una selezione, ma si sta selezionando solo i valori di alto livello e non sembra come si può costruire il resto delle parti necessarie per il mio problema: How to create LINQ Expression Tree to select an anonymous type
dinamica LINQ
Utilizzando la System.Linq.libreria dinamica, ho cercato di accedere al valore CreatedUtc
off di Bc:
query = (IQueryable<T>) query.Select(includeString + ".CreatedUtc");
Dove includeString = "B.Bc"
, ma questo mi dà un'eccezione di:
Exception thrown: 'System.Linq.Dynamic.ParseException' in System.Linq.Dynamic.dll
Additional information: No property or field 'Bc' exists in type 'List`1'
Quando includo la stringa ' "B.Bc.CreatedUtc"', ottengo questo errore: 'Informazioni aggiuntive: No proprietà o il campo 'Bc' esiste nel tipo 'List'1''. Non sembra che stia esplorando correttamente i grafici annidati? – Max
Puoi mostrare altro codice qui? –
Ho aggiornato il mio post principale. – Max