2012-02-03 9 views
10

Sto usando linq alle entità (EF). Ho un costruttore che accetta 4 parametri di stringa. A seconda del parametro non nullo, devo costruire la query linq. Posso fare con if else statement ma ho anche un altro costruttore con 10 parametri in questo caso ci saranno molte combinazioni da controllare.Clausola dynamic where in Linq alle entità

Esempio:

Constructor(p1,p2,p3,p4) 
{ 
    var prod= from p in ctxt.products.expand("items\details") 
      where p.x==p1 && p.xx==p2 && p.xxx==p3 && p.xxxx==p4 
      select p; 
} 

Nella suddetta clausola where ci dovrebbero essere controlli condizione solo se il parametro non è nullo. cioè., se p2 è nullo allora la clausola in cui dovrebbe essere simile

where p.x==p1 && p.xxx==p3 && p.xxxx==p4 

se P2 e P3 sono nulli poi

where p.x==p1 && p.xxxx==p4 

Qualcuno può dirmi come gestire questa situazione. se possibile, si può dare il codice di esempio per questo

+0

Eventuali duplicati di http://stackoverflow.com/questions/697345/linq-to-sql- need-dynamic-where-clause-over-relational-tables-help? rq = 1 –

risposta

11

Linq's DeferredExecution to rescue. La query di Linq non viene eseguita a meno che i dati non vengano richiesti da esso.

var prod = from p in ctxt.products.expand("items\details") 
     select p; 

if (p1 != null) 
{ 
    prod = prod.Where(p => p.x == p1); 
} 

if (p2 != null) 
{ 
    prod = prod.Where(p => p.xx == p2); 
} 

// Execute the query 

var prodResult = prod.ToList(); 
+0

se facciamo così caricheremo grandi quantità di dati in prod e quindi stanno prendendo sottoinsiemi di esso. Possiamo ottenere il sottoinsieme direttamente. – Deepak

+3

La query è ** NON ** eseguita fino a dopo la creazione della clausola where. Inn il codice sopra la query è costruita fino all'ultima riga ed è qui che viene eseguita. È possibile controllare questo eseguendo SQL Profiler. –

+0

Sì, sei corretto. Posso usare il tuo codice e funziona perfettamente. – Deepak

3

È possibile concatenare i metodi in base alle esigenze:

YourType(string p1, string p2, string p3, string p4) 
{ 
     var prod = ctxt.Products.Expand("items\details"); 

     if (!p1.IsNullOrWhiteSpace()) 
      prod = prod.Where(p => p.x == p1); 
     if (!p2.IsNullOrWhiteSpace()) 
      prod = prod.Where(p => p.xx == p2); 

     // .... 

     // use "prod" 
} 

Lo SQL risultante dovrebbe essere lo stesso come se li metti tutti in una singola istruzione.

+1

se facciamo così caricheremo grandi quantità di dati in prod e quindi ne stiamo prendendo sottoinsieme. Possiamo ottenere direttamente il sottoinsieme altrimenti stiamo caricando i dati non necessari – Deepak

+1

@Deepak No, non lo farai. La cosa bella di IQueryable è che non "carica i dati" - LINQ usa l'esecuzione differita, e con EF, traduce la "query" finale in una singola istruzione SQL. Questo sarà lo stesso risultato. –

+1

@Deepak Per i dettagli, consultare: http://stackoverflow.com/questions/1578778/using-iqueryable-with-linq/1578977#1578977 –

2

Si può sempre costruire la query in pezzi e approfittare di esecuzione di query ritardata:

public Constructor(int? p1, int? p2, int? p3, int? p4) 
{ 
    var prod = ctxt.products.expand("items\details"); 

    if(p1 != null) 
     prod = prod.Where(p.x == p1); 

    if(p2 != null) 
     prod = prod.Where(p.xx == p2); 

    if(p3 != null) 
     prod = prod.Where(p.xxx == p3); 

    if(p4 != null) 
     prod = prod.Where(p.xxxx == p4); 
} 
+0

se facciamo così caricheremo grandi quantità di dati in prod e quindi ne stiamo prendendo sottoinsieme. Possiamo ottenere direttamente il sottoinsieme altrimenti stiamo caricando i dati non necessari – Deepak

+1

@Deepak - Non caricherete alcun dato. LINQ non esegue la query finché non si utilizzano effettivamente i dati. Nel momento in cui viene eseguita la query, avrai già le clausole where appropriate per caricare solo i dati di cui hai bisogno. –