2013-02-06 16 views
15

Mi piacerebbe trovare un modo utilizzando Linq per filtrare una proprietà di navigazione su un sottoinsieme di entità correlate. So che tutte le risposte intorno a questo argomento suggerisco di fare un selettore anonima come ad esempio:EntityFramework 5 filtra una proprietà di navigazione inclusa

query.Where(x => x.Users.Any(y => y.ID == actingUser.ID)) 
    .Select(x => new 
    { 
     Event = x, 
     Discussions = x.Discussions.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>()) 
    }) 
    .OrderBy(x => x.Discussions.Count()) 
    .ThenBy(x => x.Event.Name); 

Tuttavia, questo è significativamente inferiore ideali a causa della natura generale della nostra generazione di query e produce anche le query SQL in modo significativo orribili se si vomitare profiler.

Mi piacerebbe essere in grado di realizzare qualcosa di simile:

query.Include(x => x.Discussions.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>())) 
     .OrderBy(x => x.Discussions.Count()) 
     .ThenBy(x => x.Name); 

mi rendo conto che questo non è supportato in EF5 (o qualsiasi versione è per questo), ma ci deve essere un modo per farlo vincolare il risultato impostato tramite Linq senza scavare in istruzioni di selezione di tipo anonime.

ho cercato di fare qualcosa per la somma di:

query.GroupJoin(discquqery, 
    x => x.ID, 
    x => x.Event.ID, 
    (evt, disc) => evt.Discussions = disc.Where(actingUser.GenerateSecurityFilterFor<Domain.Discussion>())).ToList(); 

Tuttavia non si può avere l'assegnazione all'interno di un'espressione lambda e la selezione di un tipo anonimo qui fa sì che lo stesso dilemma che lo fa utilizzando il select.

Credo che non riesco a comprendere il motivo per cui EF non fornisce un modo (che posso trovare) per generare:

SELECT 
    --Properties 
FROM Event e 
LEFT OUTER JOIN Discussions d 
    ON e.ID = d.EventID AND --Additional constraints 
WHERE 
    --Where conditions 
ORDER BY 
    --Order Conditions 

È così semplice per vincolare il join in SQL ci deve essere un modo per farlo anche attraverso Linq.

PS: Ho cercato stack, MSDN, scambio di esperti, ecc. Si prega di notare che questo non è un duplicato. Qualsiasi cosa tocchi anche questo argomento ha una risposta "non può essere fatta" o nessuna risposta. Niente è impossibile ... compreso questo.

+1

Bene, ecco una risposta "può essere fatta": http://stackoverflow.com/a/13904825/861716 –

+5

Ci sono modi per estendere il motore di generazione di query in EF. Quindi non è impossibile, e se questa è l'unica strada, la risposta è l'estensione al motore di query di EF per consentire a INNER/OUTER JOIN di contenere filtri aggiuntivi. NULLA è impossibile ... se devo ricompilare EF allora lo farò ... Non avendo una risposta esistente significa che la risposta è la costruzione di te stesso (che io al momento e anche quando ho fatto la domanda, programmato a fare) – VulgarBinary

+4

Questo è il spirito!! –

risposta

8

Tutto ciò che tocca anche su questo argomento ha una chiusura "Non può fare " risposta o nessuna risposta. Niente è impossibile ... compreso questo.

Sicuro. È possibile. È possibile scaricare il codice sorgente EF e aggiungere questa funzione. Sarà un grande contributo al progetto open source e alla comunità. Credo che il team EF ti aiuterà volentieri con i tuoi sforzi.

Con la versione corrente "non può essere eseguito" is the answer. Puoi utilizzare la proiezione su un tipo anonimo o speciale non mappato come descritto all'inizio della domanda. Altre opzioni sono query esplicite separate per caricare entità correlate per singola madre o query separata per caricare entità correlate per tutti i genitori.

rapporti di carico per singolo genitore:

context.Entry(event) 
     .Collection(e => e.Discussions) 
     .Query() 
     .Where(d => ...) 
     .Load(); 

rapporti di carico per tutti i genitori (richiede il caricamento pigro per essere spento):

// load all parents 
var events = query.Where(e => ...).ToList(); 

// load child filtered by same condition for parents and new condition for children 
childQuery.Where(d => e.Event ... && d.Something ...).Load(); 

La seconda soluzione richiede bambino ad avere proprietà di navigazione di nuovo a genitore (per la costruzione della stessa condizione di interrogazione utilizzata inizialmente per caricare il genitore).Se hai tutto correttamente configurato e le entità sono collegate, EF dovrebbe correggere automaticamente le tue relazioni (raccolte) in entità padre (ma non contrassegnerà la raccolta nel proxy dinamico come caricata, quindi questo è il motivo per cui non puoi usarlo insieme al caricamento lento).

+0

quindi a quanto pare sto estendendo il core EF5. Sai se esiste un modo per estendere invece di modificare e ricompilare l'intera DLL? – VulgarBinary

+1

Sarà necessario ricompilare la DLL. Puoi visitare [sito codeplex EF] (http://entityframework.codeplex.com/discussions) e discutere direttamente questo contributo con il team EF: potrebbero avere già alcuni progetti di alto livello per questa funzione e condividerli con te. –

+3

Vota per filtrare Include [qui] (https://entityframework.codeplex.com/workitem/47)! – Chris

Problemi correlati