web-dev-qa-db-de.com

Die 2100-Parametergrenze (SQL Server) bei Verwendung von Contains ()

from f in CUSTOMERS
where depts.Contains(f.DEPT_ID)
select f.NAME

depts ist eine Liste (IEnumerable<int>) von Abteilungs-IDs

Diese Abfrage funktioniert gut, bis Sie eine große Liste übergeben (etwa um 3000 ID-IDs). Dann erhalte ich diesen Fehler:

Der RPC-Protokolldatenstrom für eingehende tabellarische Datenströme (TDS) ist falsch. In dieser RPC-Anforderung wurden zu viele Parameter angegeben. Das Maximum ist 2100.

Ich habe meine Anfrage geändert in: 

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

mit IndexOf() wurde der Fehler behoben, die Abfrage wurde jedoch langsam. Gibt es eine andere Möglichkeit, dieses Problem zu lösen? vielen Dank.

54
ban-G

Meine Lösung (Guides -> List of 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;
11
ADM-IT

Warum schreiben Sie die Abfrage nicht in SQL und hängen Ihre Entität an?

Es ist schon eine Weile her, seit ich in Linq gearbeitet habe, aber hier heißt es:

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

Natürlich müssen Sie sich vor Injektionen schützen, aber das sollte nicht zu schwer sein.

6
Joel

Sie sollten sich das LINQKit-Projekt ansehen , da sich irgendwo eine Technik zum Bündeln solcher Anweisungen befindet, um dieses Problem zu lösen. Ich glaube, die Idee ist die Verwendung des PredicateBuilder, um die lokale Sammlung in kleinere Stücke zu unterteilen, aber ich habe die Lösung nicht im Detail geprüft, weil ich stattdessen nach einer natürlicheren Methode gesucht habe, um damit umzugehen.

Leider scheint es aus Microsofts Antwort auf meinen Vorschlag , um dieses Verhalten zu beheben, dass keine Pläne festgelegt wurden, um dies für .NET Framework 4.0 oder sogar nachfolgende Service Packs adressieren zu lassen.

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

AKTUALISIEREN:

Ich habe einige Diskussionen darüber eröffnet, ob dies für LINQ to SQL oder das ADO.NET Entity Framework in den MSDN-Foren behoben werden sollte. In diesen Beiträgen finden Sie weitere Informationen zu diesen Themen und die temporäre Problemumgehung, die ich mit XML und einer SQL-UDF gefunden habe.

2
jpierson

Ich hatte ein ähnliches Problem und es gab zwei Möglichkeiten, das Problem zu beheben.

  1. Schnitt Methode
  2. iDs beitreten

Um Werte zu erhalten, die NICHT in der Liste enthalten sind, habe ich die linke Verknüpfung von Except method OR verwendet.

1
Roman O

Sie können Ihre Liste der Abteilungen immer in kleinere Mengen unterteilen, bevor Sie sie als Parameter an die von Linq generierte IN-Anweisung übergeben. Siehe hier:

Ein großes IEnumerable in ein kleineres IEnumerable mit einem festen Artikelbetrag teilen

0
Stephen Burns