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

depts jest lista (IEnumerable<int>) identyfikatorów towarowychBicie 2100 graniczną parametr (SQL Server) przy użyciu Zawiera()

Ta kwerenda działa dobrze, dopóki nie przejdą dużą listę (powiedzmy około 3000 dept identyfikatorów) .. następnie uzyskać ten błąd:

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.

zmieniłem maila do:

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

przy użyciu IndexOf() naprawił błąd, ale spowolnił kwerendę. Czy istnieje inny sposób rozwiązania tego problemu? Dzięki wielkie.

+1

Jak o [jak tak] (http://stackoverflow.com/questions/567963/linq-expression-to-return-property-value/568771#568771) (który dozuje go w łatwe do opanowania części).Pozostałe (inne niż LINQ) opcje obejmują CSV i "split" UDF oraz parametry wycenione w tabeli (w SQL2008). –

+0

Mark, czy możesz wyjaśnić, jaka jest najlepsza alternatywa dla "zawierać", jeśli mam różne parametry od 1 do 2000? Wiem, że to tworzy garść planów w db, ale wydaje się, że użycie 'jak '% %'' zajmie jeszcze więcej czasu zasobów db. Co powinienem użyć? –

+0

Problem z limitem 2100 parametrów nie istnieje w Entity Framework: http://stackoverflow.com/questions/8898564/entity-framework-hitting-2100-parameter-limit – nmit026

Odpowiedz

6

Dlaczego nie napisać zapytanie w sql i załączyć swój podmiot?

Minęło trochę czasu od kiedy pracował w Linq, ale tu idzie:

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

Oczywiście, trzeba będzie chronić przed wstrzyknięciem, ale to nie powinno być zbyt trudne.

+0

dzięki joel. pozwól mi spróbować, a dam ci znać, jak to działa. –

+10

Zastrzeżenie: to jest w porządku z liczbami całkowitymi, ale z ciągami: uważaj na iniekcję SQL. –

+1

Prawdopodobnie chcesz gdzieś tam przecinek, Joel? –

2

Będziesz chciał sprawdzić LINQKit project, ponieważ tam gdzieś jest technika do grupowania takich stwierdzeń, aby rozwiązać ten problem. Sądzę, że chodzi o to, aby użyć PredicateBuilder, aby podzielić lokalną kolekcję na mniejsze chunck, ale nie sprawdziłem szczegółowo rozwiązania, ponieważ szukałem bardziej naturalnego sposobu radzenia sobie z tym.

Niestety, z poziomu pojawia się problem polegający na naprawieniu tego zachowania, które nie zostało ustawione, aby było adresowane do programu .NET Framework 4.0 lub do kolejnych dodatków Service Pack.

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

UPDATE:

Mam otworzył dyskusję dotyczącą tego, czy to miał być ustalony dla LINQ to SQL lub ADO.NET Entity Framework na forach MSDN. Zobacz te posty, aby uzyskać więcej informacji na te tematy i zobaczyć tymczasowe obejście, które wymyśliłem przy użyciu XML i UDF SQL.

1

Miałem podobny problem i mam dwa sposoby, aby to naprawić.

  1. Intersect metoda
  2. dołączyć na identyfikatorach

Aby uzyskać wartości, które nie znajdują się w wykazie, użyłem Except metoda lub LEFT JOIN.

+2

Czy możesz podać przykład, jak to zrobić? –

10

Moje rozwiązanie (Poradniki -> Lista 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

Zamiast używać sufitu (i pomnażania w przeskakiwaniu) i inkrementacji o 1, po prostu użyj Count dla warunku i inkrementacji do 2000. Uczyń też stałą, aby była konfigurowalna. – webXL

Powiązane problemy