LinqToSQL в статье - PullRequest
       2

LinqToSQL в статье

1 голос
/ 26 января 2011

Я пытаюсь использовать LinqToSQL для генерации предложения IN, которое может содержать много элементов.Мой оригинальный код был что-то вроде:

context.Employees.Where(p => EmployeeIDs.Contains(p.EmployeeID));

, что в итоге создает предложение in с каждым идентификатором сотрудника в качестве параметра SQL.Проблема в том, что если вы укажете 2100 параметров, выдается исключение.Я работал над этим в другом месте своего приложения, выполняя несколько запросов и комбинируя результаты.Это работает нормально в простых случаях, но сейчас я делаю что-то более сложное и не думаю, что это лучшее решение.

В любом случае, Contains генерирует что-то вроде

EmployeesID IN (@p0, @p1, @p2)

Но есть ли способ убедить его сделать это?

EmployeesID IN (23, 582, 3948)

Я начал идти по пути использования примера динамического запроса, но потом понял, что он, похоже, предназначен только для написания динамического кода linq., не динамический sql.Затем я обнаружил ExecuteQuery, но я не хочу создавать всю строку запроса вручную, а только отдельные разделы запроса, которые я хочу.

Чтобы быть более конкретным, я хотел бы что-то вроде:

context.Employees
    .Where(p => p.Active == true)
    .Where("EmployeeID IN (23, 582, 3948)");

Или предпочтительно (если это сгенерирует IN без использования параметров):

context.Employees
    .Where(p => p.Active == true)
    .Where(p => p.In("EmployeeID", EmployeeIDs));

Есть ли способ сделать это?Благодаря.

Ответы [ 2 ]

0 голосов
/ 27 января 2011

Проблема здесь в ограничении 2100 параметров.Это жесткий предел, определенный SQL.Не ADO.NET или LINQ.Я сам столкнулся с этой стеной пару недель назад.Так как LINQ всегда будет параметризировать ваши запросы, пути к этому нет.Вам придется пакетировать ваши звонки или использовать ExecuteQuery.Но если вы используете ExecuteQuery, убедитесь, что вы выполняете собственную проверку параметров, чтобы избежать атак с использованием SQL-инъекций.

0 голосов
/ 26 января 2011

Можно ли определить запрос, который будет возвращать необходимые идентификаторы сотрудников, основываясь на каком-либо другом запросе? Если это так, вы можете определить поиск, используя вложенный запрос:

var employeeIds = from x in context.EitherEmployeesOrSomeOtherRecords
   where x.SomeConditionIsTrue
   select x.EmployeeID; //not yet evaluated; employeeIds is an IQueryable

var employees = from e in context.Employees
   where employeeIds.Contains(x.EmployeeID)
   select e;

Этот запрос LINQ будет преобразован Linq2SQL в один оператор SQL с использованием предложения EXISTS для проверки SQL-эквивалента подзапроса employeeIds.

Что касается принуждения Linq2SQL к указанию значений из кода в виде литералов, я не думаю, что вы можете, но я могу ошибаться.

РЕДАКТИРОВАТЬ: Хорошо, а что если вы сделали логику, определяющую, как построить запрос умнее? Например, если у вас есть кнопка или флажок «выбрать все», вы можете использовать ее для создания более простого запроса: «подтянуть всех сотрудников, которые были бы выбраны для списка»:

var employees = from e in context.Employees
   where TheSameConditionThatCausedItToBeInTheList == true
   select e;

Если пользователь выбрал все, а затем отменил выбор нескольких, вы можете обнаружить это (больше выбранных, чем нет) и вместо этого вывести «все сотрудники, КРОМЕ X, Y и Z»:

var notChecked = uiList.Items.Except(uiList.SelectedItems).Select(x=>x.EmployeeID)

var employees = from e in context.Employees
   where !notChecked.Contains(e.EmployeeID)
   select e;

Если у вас более 4200 сотрудников, описанное выше не всегда будет работать (вы можете выбрать более 2100, но оставить более 2100 невыбранными, так что это в любом случае будет взорвано), но я также не могу представить список 4200 элементов, которые также не позволяют выбирать на основе какого-либо другого показателя (т. Е. Отдела), что позволяет выполнить запрос типа «подтянуть всех сотрудников в отделах X, Y и Z, а также сотрудников A, B и C»:

var metaSelection = departmentList.SelectedItems.Select(x=>x.DepartmentID);

var exceptions = uiList.SelectedItems.Where(x=>!metaSelection.Contains(x.DepartmentID))
                       .Select(x=>x.EmployeeID);

var employees = from e in context.Employees
    where metaSelection.Contains(e.DepartmentID)
    || exceptions.Contains(e.EmployeeID)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...