Проблема : Nhibernate анализирует каждое значение в sql "WHERE IN ()" как параметры, и сервер MS SQL не поддерживает достаточное количество параметров (более 2000).
Я использую Nhibernate с Linq для извлечения моих данных с сервера SQL, и мне нужно загрузить множество объектов на основе уже известных идентификаторов.
Мой код выглядит примерно так:
int[] knownIds = GetIDsFromFile();
var loadedEntities = _Repository.GetAll()
.Where(x => knownIds.Contains(x.ID))
.ToList();
, которые дают sql, как это:
SELECT id, name FROM MyTable
WHERE id IN (1 /* @p0 */,2 /* @p1 */,3 /* @p2 */,4 /* @p3 */, 5 /* @p4 */)
Если в knownIds слишком много значений, этот код вызовет исключение из-за множества параметров, используемых NHibernate.
Я думаю, что лучшим решением было бы, если бы я мог заставить NHibernate использовать только 1 параметр для всего "WHERE IN ()", но я не знаю, как это сделать:
SELECT id, name FROM MyTable WHERE id IN (1, 2, 3, 4, 5 /* @p0 */)
Я буду рад услышать любые идеи о том, как решить эту проблему - либо путем расширения поставщика LINQ, либо другими способами. Одним из решений является простое выполнение запроса x раз (knownIds.Count / 1000), но я бы предпочел универсальное решение, которое работало бы для всех моих сущностей.
Я пытался расширить возможности поставщика LINQ с помощью поиска в Google и Stackoverflow, однако не могу найти решения и не имею опыта работы с HQL или построителем дерева.
Вот несколько сайтов, на которых я был:
UPDATE:
Я знаю, что это не очень хорошая практика - иметь так много значений в предложении IN, но я не знаю лучшего решения для того, что я хочу сделать.
Рассмотрим компанию, в которой все клиенты платят за услуги компании один раз в месяц. Компания не обрабатывает платежи сама, но имеет другую компанию для сбора денег. Один раз в месяц компания получает файл с информацией о состоянии этих платежей: были ли они оплачены или нет. Файл содержит только идентификатор конкретного платежа, а не идентификатор клиента.
Компания с 3000 ежемесячных клиентов будет делать 3000 LogPayments каждый месяц, где статус должен быть обновлен. Через 1 год будет около 36 000 LogPayments, поэтому просто загрузить их все тоже не кажется хорошим решением.
МОЕ РЕШЕНИЕ:
Спасибо за все полезные ответы. В конце концов я решил использовать комбинацию ответов. Для этого конкретного случая я сделал что-то вроде того, что предложил Четвертый, поскольку это значительно повысило бы производительность. Однако я также реализовал общий метод, предложенный Стефаном Стейнеггером, потому что мне нравится, что я могу сделать это, если это то, чего я действительно хочу. Кроме того, я не хочу, чтобы моя программа аварийно завершала работу, поэтому в будущем я также буду использовать этот метод ContainsAlot в качестве защиты.