2010-08-17 11 views
10

Ho una relazione tabella padre-figlio. In un repository, sto facendo questo:EF prende sempre per generare questa query

return (from p in _ctx.Parents 
.Include("Children") 
select p).AsQueryable<Parent>(); 

Poi in un filtro, voglio filtrare il genitore da un elenco di ID figlio:

IQueryable<Parent> qry; // from above 
List<int> ids; // huge list (8500) 
var filtered = 
from p in qry.Where(p => p.Children.Any(c => ids.Contains(c.ChildId))) select s; 

mio elenco di ID è enorme. Questo genera una semplice istruzione SQL che ha un enorme elenco di ID "in (1,2,3 ...)", ma non ci vuole tempo apprezzabile per funzionare da solo. EF, tuttavia, impiega un minuto intero solo per generare la dichiarazione. Ho provato questo impostando un breakpoint e chiamando:

((ObjectQuery<Parent>)filtered).ToTraceString(); 

Questo richiede tutto il tempo. Il problema è nella mia ultima dichiarazione di linq? Non conosco altro modo per fare l'equivalente di Child.ChildId in (id). E anche se la mia affermazione di linq è negativa, come mai nel mondo ci vorrà così tanto tempo?

+0

Posta lo schema e lo sql generato, potresti ricevere ulteriore assistenza. –

+0

Lo schema non sembra avere importanza, né la relazione genitore/figlio. Stesso problema selezionando solo da una singola tabella/entità con una lista grande. – dudeNumber4

+0

Per chiunque si trovi di fronte al problema; da tutto ciò che posso dire, non c'è soluzione con EF4. È necessario ricorrere alle procedure memorizzate. Maggiori informazioni: http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/d629c798-db45-4a04-9813-a3b565d87c83 – dudeNumber4

risposta

2

Riscrivi la tua query nella sintassi Lambda e ridurrà il tempo di almeno 3 secondi (o almeno lo ha fatto per il mio progetto EF).

return _ctx.Parents.Include("Children").AsQueryable<Parent>(); 

e

IQueryable<Parent> qry; // from above 
List<int> ids; // huge list (8500) 
var filtered = qry.Where(p => p.Children.Any(c => ids.Contains(c.ChildId))); 
+0

'Seleziona (s => s)' non fa nulla. Finiscila dopo il Dove. – StriplingWarrior

+0

Giusto ... Grazie! –

+0

Questo non ha fatto differenza nel mio caso. – dudeNumber4

4

Purtroppo, la creazione di query in LINQ to Entities è un successo piuttosto pesante, ma ho trovato che di solito consente di risparmiare tempo grazie alla possibilità di creare query dai loro parti componenti prima effettivamente colpire il database.

È probabile che il modo in cui implementano il metodo Contains utilizzi un algoritmo che presuppone che Contiene sia generalmente utilizzato per un set di dati relativamente piccolo. Secondo i miei test, la quantità di tempo impiegata per ID nell'elenco inizia a salire alle stelle intorno a 8000.

Quindi potrebbe essere utile suddividere la query in pezzi. Raggruppali in gruppi di 1000 o meno e concatena un gruppo di espressioni Where.

var idGroups = ids.GroupBy(i => i/1000); 
var q = Parents.Include("Children").AsQueryable(); 
var newQ = idGroups.Aggregate(q, 
    (s, g) => s.Concat(
        q.Where(w => w.Children.Any(wi => g.Contains(wi.ChildId))))); 

Questo accelera le cose in modo significativo, ma potrebbe non essere sufficiente in modo significativo per i vostri scopi, nel qual caso si dovrà ricorrere ad una stored procedure. Sfortunatamente, questo particolare caso d'uso non si adatta alla "scatola" del comportamento previsto di Entity Framework. Se il tuo elenco di ID potrebbe iniziare come una query dallo stesso Contesto entità, Entity Framework avrebbe funzionato correttamente.

+0

Suvviato, ma non ha contrassegnato come risposta. L'utilizzo di stored procs è la risposta, ma non ho intenzione di utilizzare la soluzione di query interrotta. Userò semplicemente la soluzione EF rotta ... – dudeNumber4

+0

Ti incoraggerei a iniziare una taglia o a segnare una risposta. Anche se scrivi la tua risposta basata su stored proc nella tua domanda, le FAQ indicano chiaramente che questo è accettabile.Naturalmente, vorrei anche sottolineare che non solo ho risposto alla domanda come richiesto, ma ho anche fornito la soluzione che sembra abbia intenzione di usare. – StriplingWarrior

+0

Questa è probabilmente la migliore risposta che otterrete. A corto di qualcuno che esce con una correzione per il framework, questa è la risposta. –

Problemi correlati