Atteindre la limite de paramètre de 2100 (SQL Server) lors de L'utilisation de Contains()

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

depts est une liste ( IEnumerable<int> ) des noms de département

cette requête fonctionne très bien jusqu'à ce que vous passiez une grande liste (disons environ 3000 départements) .. puis j'obtiens cette erreur:

le flux du protocole D'appel de procédure à distance (RPC) pour le flux de données tabulaires entrant (TDS) est incorrect. Trop de paramètres ont été fournis dans cette demande de RPC. Le maximum est 2100.

j'ai changé ma requête en:

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

en utilisant IndexOf() a corrigé l'erreur mais a fait la requête lente. Est-il un autre moyen pour résoudre ce problème? merci beaucoup.

53
demandé sur marc_s 2009-03-18 00:47:16

5 réponses

ma solution (Guides - > liste des guides):

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
répondu ADM-IT 2014-02-11 17:50:15

pourquoi ne pas écrire la requête en sql et joindre votre entité?

ça fait longtemps que je n'ai pas travaillé à Linq, mais voilà:

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

bien sûr, vous aurez besoin de protéger contre l'injection, mais cela ne devrait pas être trop difficile.

6
répondu Joel 2009-03-17 22:36:19

vous voudrez consulter le LINQKit project car il y a quelque part une technique pour assembler de telles déclarations pour résoudre ce problème. Je crois que l'idée est d'utiliser le PredicateBuilder pour briser la collection locale en petits morceaux, mais je n'ai pas examiné la solution en détail parce que j'ai plutôt été à la recherche d'une façon plus naturelle de gérer cela.

malheureusement, il apparaît de la réponse de Microsoft à ma suggestion pour corriger ce comportement qu'il n'y a pas de plan défini pour avoir cette adresse pour .net Framework 4.0 ou même des paquets de service ultérieurs.

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

mise à jour:

j'ai ouvert une discussion pour savoir si cela allait être fixé pour LINQ à SQL ou le ADO.NET Entity Framework sur les forums MSDN. S'il vous plaît voir ces messages pour plus d'informations sur ces sujets et de voir la solution de contournement temporaire que j'ai trouvé en utilisant XML et un UDF SQL.

2
répondu jpierson 2009-10-06 20:46:04

j'ai eu le même problème, et j'ai deux solutions pour y remédier.

  1. Intersect method
  2. rejoindre sur Id

pour obtenir des valeurs qui ne sont pas dans la liste, j'ai utilisé sauf méthode ou gauche joindre.

1
répondu Roman O 2012-11-12 14:05:45

vous pouvez toujours diviser votre liste de depts en plus petits ensembles avant de les passer comme paramètres à L'instruction in générée par Linq. Voir ici:

diviser un grand IEnumerable en plus petit IEnumerable d'un montant fixe de l'article

0
répondu Stephen Burns 2017-05-23 12:00:28