Достижение предела параметра 2100 (SQL Server) при использовании Contains()

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

depts — это список (IEnumerable<int>) идентификаторов отделов.

Этот запрос работает нормально, пока вы не передадите большой список (скажем, около 3000 идентификаторов отделов). Затем я получаю эту ошибку:

Неверный поток протокола удаленного вызова процедур (RPC) входящего потока табличных данных (TDS). В этом запросе RPC указано слишком много параметров. Максимум 2100.

Я изменил свой запрос на:

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

использование IndexOf() исправило ошибку, но сделало запрос медленным. Есть ли другой способ решить эту проблему? Спасибо.


person ban-G    schedule 17.03.2009    source источник
comment
Как насчет так (который объединяет его в управляемые части) . Другие (не LINQ) параметры включают CSV и разделенную пользовательскую функцию, а также табличные параметры (в SQL2008).   -  person Marc Gravell    schedule 18.03.2009
comment
Марк, не могли бы вы объяснить, что является лучшей альтернативой contain, если у меня есть различные параметры от 1 до 2000? Я знаю, что это создает кучу планов в БД, но кажется, что использование like <input parameter> '%<search field>%' займет еще больше времени ресурсов БД. Что я должен использовать?   -  person Johnny_D    schedule 15.10.2013
comment
Проблема с ограничением параметра 2100 не существует в Entity Framework: "> stackoverflow.com/questions/8898564/   -  person nmit026    schedule 01.12.2016
comment
Вы пробовали какое-либо решение? не отмечено   -  person Kiquenet    schedule 13.03.2017
comment
Как насчет того, что при поиске DEPT_id, когда он равен 1, будет найден любой идентификатор, имеющий 1 в любой цифре! Я что-то упускаю?   -  person A.Akram    schedule 17.09.2017


Ответы (5)


Мое решение (Guids — это список идентификаторов, по которым вы хотите отфильтровать):

List<MyTestEntity> result = new List<MyTestEntity>();
for(int i = 0; i < Math.Ceiling((double)Guids.Count / 2000); i++)
{
    var nextGuids = Guids.Skip(i * 2000).Take(2000);
    result.AddRange(db.Tests.Where(x => nextGuids.Contains(x.Id)));
}
this.DataContext = result;
person ADM-IT    schedule 11.02.2014
comment
Вместо использования Потолка (и умножения в Skip) и увеличения на 1, просто используйте Count для условия и увеличьте на 2000. Также сделайте его константой, чтобы сделать его настраиваемым. - person webXL; 17.10.2014

Почему бы не написать запрос в sql и не прикрепить свою сущность?

Прошло некоторое время с тех пор, как я работал в Linq, но вот:

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

Конечно, вам нужно будет защититься от инъекций, но это не должно быть слишком сложно.

person Joel    schedule 17.03.2009
comment
спасибо Джоэл. позвольте мне попробовать, и я дам вам знать, как это происходит. - person ban-G; 18.03.2009
comment
Предостережение: с целыми числами это нормально, но со строками: следите за внедрением SQL. - person Marc Gravell; 18.03.2009
comment
По-видимому, тебе нужна запятая где-то там, Джоэл? - person Marc Gravell; 18.03.2009
comment
Да, внедрение всегда вызывает беспокойство при написании динамического SQL, но с целыми числами вы в большей безопасности. Добавлена ​​запятая. ;) - person Joel; 18.03.2009
comment
привет Джоэл, еще раз спасибо, что нашли время, чтобы ответить на мой вопрос. :-) - person ban-G; 19.03.2009
comment
@ Джордж, если вы дочитаете до конца (или комментарии), вы заметите, что я предупредил о риске инъекции. - person Joel; 03.05.2012
comment
Некрасиво, но как-то красивое обходное решение :) Почему существует ограничение на количество параметров? - person yonexbat; 03.07.2013
comment
Я почти уверен, что если оператор станет достаточно большим, вы все равно достигнете предела. Я думаю, что это было 65 тысяч символов в какой-то момент? - person jocull; 09.12.2016

Вам следует ознакомиться с проектом LINQKit, так как где-то внутри него есть технология пакетной обработки. до таких заявлений, чтобы решить эту проблему. Я считаю, что идея состоит в том, чтобы использовать PredicateBuilder для разбиения локальной коллекции на более мелкие фрагменты, но я не рассматривал решение подробно, потому что вместо этого я искал более естественный способ справиться с этим.

К сожалению, это появляется из ответа Microsoft на мое предложение исправить это. поведение, что нет никаких планов по устранению этого для .NET Framework 4.0 или даже последующих пакетов обновлений.

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

ОБНОВИТЬ:

Я начал дискуссию о том, будет ли это исправлено для LINQ to SQL или ADO.NET Entity Framework на форумах MSDN. Пожалуйста, ознакомьтесь с этими сообщениями для получения дополнительной информации по этим темам и временного обходного пути, который я придумал, используя XML и SQL UDF.

person jpierson    schedule 04.08.2009

У меня была аналогичная проблема, и у меня было два способа ее исправить.

  1. Метод Intersect
  2. присоединиться к идентификаторам

Чтобы получить значения, которых нет в списке, я использовал метод Except ИЛИ левое соединение.

Обновить

EntityFramework 6.2 успешно выполняет следующий запрос:

var employeeIDs = Enumerable.Range(3, 5000);
var orders =
    from order in Orders
    where employeeIDs.Contains((int)order.EmployeeID)
    select order;
person Roman O    schedule 12.11.2012
comment
Не могли бы вы привести пример, как это сделать? - person Philipp M; 10.02.2014

Вы всегда можете разделить свой список отделов на более мелкие наборы, прежде чем передавать их в качестве параметров оператору IN, сгенерированному Linq. Глянь сюда:

Разделите большой IEnumerable на более мелкие IEnumerable фиксированного количества элементов

person Stephen Burns    schedule 23.05.2015