Проблема: Nhibernate анализирует каждое значение в параметрах "WHERE IN()" sql в качестве параметров, а сервер 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 times (knownIds.Count/1000), но я скорее хочу, чтобы общее решение работало для всех моих объектов.
Я попытался расширить возможности LINQ-провайдера, выполнив поиск в google и Stackoverflow, однако я не могу найти решение, и у меня нет опыта работы ни с HQL, ни с деревом. Вот несколько сайтов, на которых я был:
- Расширение провайдера LINQ to Nhibernate в сочетании с проблемой Dynamic LINQ
- расширение NHibernate LINQ
- Исходный код: NHibernate/Linq/Functions/QueryableGenerator.cs
UPDATE:
Я знаю, что это не очень хорошая практика, поскольку у меня так много значений в предложении IN, но я не знаю лучшего решения для того, что я хочу делать.
Рассмотрим компанию, в которой все клиенты платят за услуги компании один раз в месяц. Компания не обрабатывает сами платежи, но имеет другую компанию для сбора денег. Один раз в месяц компания получает файл, содержащий статус этих платежей: если они были оплачены или нет. Файл содержит только идентификатор конкретного платежа, а не идентификатор клиента.
Компания с 3000 ежемесячными клиентами будет составлять 3000 LogPayments каждый месяц, когда статус должен быть обновлен. Через 1 год будет около 36 000 LogPayments, поэтому просто загрузить их все тоже не будет хорошим решением.
МОЕ РЕШЕНИЕ: Спасибо за все полезные ответы. В конце концов я решил использовать комбинацию ответов. В этом конкретном случае я сделал что-то вроде четвертого предложения, так как это значительно увеличило бы производительность. Однако я также внедрил общий метод, предложенный Стефаном Штайнеггером, потому что мне нравится, что я могу это сделать, если это то, чего я действительно хочу. Кроме того, я не хочу, чтобы моя программа вылетала с ошибкой, поэтому в будущем я также использую этот метод ContainsAlot как гарантию.