2009-03-17 7 views
51
from f in CUSTOMERS 
where depts.Contains(f.DEPT_ID) 
select f.NAME 

depts è una lista (IEnumerable<int>) di ID repartoColpire 2100 limite del parametro (SQL Server) quando si utilizza Contiene()

Questa query funziona bene fino a quando si passa un elenco di grandi dimensioni (ad esempio circa 3000 ids dept) .. poi ottengo questo errore:

The incoming tabular data stream (TDS) remote procedure call (RPC) protocol stream is incorrect. Too many parameters were provided in this RPC request. The maximum is 2100.

ho cambiato la mia domanda a:

var dept_ids = string.Join(" ", depts.ToStringArray()); 
from f in CUSTOMERS 
where dept_ids.IndexOf(Convert.ToString(f.DEPT_id)) != -1 
select f.NAME 

utilizzando IndexOf() ha corretto l'errore ma ha rallentato la query. C'è un altro modo per risolvere questo? grazie mille.

+1

Come su [in questo modo] (http://stackoverflow.com/questions/567963/linq-expression-to-return-property-value/568771#568771) (che fabbricazioni in pezzi gestibili).Le altre opzioni (non LINQ) includono CSV e una UDF "divisa" e parametri con valori di tabella (in SQL2008). –

+0

Mark, puoi spiegare quale è la migliore alternativa a 'contain' se ho vari parametri che contano da 1 a 2000? So che questo crea un sacco di piani in db, ma sembra che l'uso di 'like '% %'' richiederà ancora più tempo di risorse db. Cosa dovrei usare? –

+0

Il problema del limite di parametro 2100 non esiste in Entity Framework: http://stackoverflow.com/questions/8898564/entity-framework-hitting-2100-parameter-limit – nmit026

risposta

6

Perché non scrivere la query in sql e allegare la propria entità?

E 'passato del tempo da quando ho lavorato in LINQ, ma qui va:

IQuery q = Session.CreateQuery(@" 
     select * 
     from customerTable f 
     where f.DEPT_id in (" + string.Join(",", depts.ToStringArray()) + ")"); 
q.AttachEntity(CUSTOMER); 

Naturalmente, sarà necessario per la protezione contro l'iniezione, ma che non dovrebbe essere troppo difficile.

+0

grazie joel. fammi provare e ti farò sapere come va. –

+10

Attenzione: va bene con numeri interi, ma con stringhe: fai attenzione all'iniezione SQL. –

+1

Presumibilmente vuoi una virgola da qualche parte, Joel? –

2

Si consiglia di controllare il LINQKit project poiché da qualche parte c'è una tecnica per il dosaggio di tali istruzioni per risolvere questo problema. Credo che l'idea sia di utilizzare PredicateBuilder per rompere la raccolta locale in chuncks più piccoli, ma non ho esaminato la soluzione in dettaglio perché ho cercato invece un modo più naturale per gestirlo.

Sfortunatamente appare da Microsoft's response to my suggestion per risolvere questo comportamento che non ci sono piani impostati per avere questo indirizzamento per .NET Framework 4.0 o anche i successivi service pack.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=475984

UPDATE:

Ho aperto una discussione per quanto riguarda se questo stava per essere fissato per LINQ to SQL o ADO.NET Entity Framework sui forum MSDN. Si prega di consultare questi post per ulteriori informazioni su questi argomenti e per vedere la soluzione temporanea che ho trovato usando XML e una UDF SQL.

1

Ho avuto un problema simile e ho avuto due modi per risolverlo.

  1. Intersect metodo
  2. uniscono sugli ID

Per ottenere valori che non sono nella lista, ho usato Except metodo o LEFT JOIN.

+2

Puoi fare un esempio su come farlo? –

10

La mia soluzione (Guide -> Elenco dei Guid):

List<tstTest> tsts = new List<tstTest>(); 
for(int i = 0; i < Math.Ceiling((double)Guides.Count/2000); i++) 
{ 
    tsts.AddRange(dc.tstTests.Where(x => Guides.Skip(i * 2000).Take(2000).Contains(x.tstGuid))); 
} 
this.DataContext = tsts; 
+1

Piuttosto che usare Ceiling (e moltiplicando in Skip) e incrementare di 1, basta usare Count per la condizione e incrementare di 2000. Rendilo costante per renderlo configurabile. – webXL