2010-09-09 3 views
0

Использование хранимых процедур TSQL, динамические запросы были cinch. Например, скажем, у меня было приложение для отчетов, которое, возможно, запросило архивные записи. Хранимая процедура будет выглядеть так:Динамические запросы в LINQ to Entities

DECLARE @sql nvarchar(MAX) 
DECLARE @join nvarchar(MAX) 
DECLARE @where nvarchar(MAX) 

IF @optionalvar1 IS NOT NULL 
    SET @where = COALESCE(@where, '') + 
    'AND SomeColumn = ' + @optionalvar1 + ' ' 

IF @optionalvar2 IS NOT NULL 
    BEGIN 
    SET @join = COALESCE(@join, '') + 
    'LEFT JOIN SomeTable s 
    ON st.Column = s.Column ' 

    SET @where = COALESCE(@where, '') + 
    'AND s.SomeColumn = ' + @optionalvar2 + ' ' 
    END 

SET @sql = 
' 
SELECT 
    * 
FROM 
    StaticTable st 
    ' + COALESCE(@join, '') + ' 
WHERE 
    1=1 
    ' + COALESCE(@where, '') + ' 
' 

Запрещая глупые опечатки, вот как я делал динамические запросы раньше. Для каждого нового необязательного параметра я добавляю еще один условный блок и добавляю необходимое соединение и код (и адаптирую модель, если мне нужно также добавить порядок и т. Д.). Я пытаюсь понять, как это сделать в Entities, но у меня время от времени.

Большинство ссылок, которые я нашел (http://naspinski.net/post/Writing-Dynamic-Linq-Queries-in-Linq-to-Entities.aspx в частности) показывают, как искать динамически изменяющуюся строку, используя этот битый код:

var data = ctx.table.Where(b => b.branch_id == 5 || b.display == "Hello"); 

Я не думаю, что это работает в моем примере, как я нужно динамически добавлять н-число дополнительных, где положения и, возможно, включается в зависимости от того, какие переменные передаются в

Я надеялся, что я мог сделать что-то простое, как:.

var query = 
     (from t in ctx.Table 
     select t); 

    if (optionalvar1) 
    { 
     query = query.Join('etc'); 
     query = query.Where('etc'); 
    } 

Но не сделал большого прогресса (не могу понять синтаксис, чтобы заставить их делать то, что я хочу.

Любые идеи? Я подхожу к этому неправильно? Есть ли лучшее, более простое решение? Я знаю, что в конце дня у меня всегда может быть множество условных проверок для каждого возможного набора комбинаций, а затем генерация всего запроса LINQ в этом блоке, но количество требуемых там копий-макарон вызывает разочарование.

ответ

3

Проблема в том, что вы не используете результат статьи Where. Просто вызывая Where, и игнорирование возвращаемого значения не изменит то, что находится в query. С стыки это может быть несколько сложнее, но без них это легко:

if (someCondition) 
{ 
    query = query.Where(x => x.Text == "Some value"); 
} 

Если вы можете дать более подробную информацию о том, что ваш присоединяется нужно сделать, мы можем, вероятно, что-то слишком.

Обратите внимание, что, насколько я вижу, ваша динамическая версия SQL была бы уязвима для атак SQL-инъекций, btw - что-то, что не соответствует LINQ.

+0

К сожалению, не в состоянии установить запрос = query.Where был больше опечатка, чем ничего. Моя основная проблема заключается в том, как выразить мой запрос внутри .Where bit. Я не могу работать с объектом «x» - это POCO, содержащий конечный результат моего запроса. Однако в большинстве случаев мне нужно сделать предложение where в других таблицах, участвующих в запросе, но не обязательно возвращаться в конечном объекте. Я уточню вопрос, чтобы уточнить. (Кроме того, переменные, переданные в динамический SQL, происходят из параметризованных запросов в .NET и получают excused с помощью sp_executesql - должно быть нормально (?).) – rake

+2

@rake: Это выглядит так, как будто это только POCO, но LINQ to Entities будет фактически преобразовать их в SQL. Немного о требовании вещей, отсутствующих в остальной части запроса, трудно говорить без конкретного примера. И нет, я не считаю, что ваш динамический SQL безопасен от атак SQL-инъекций только потому, что они параметризованы в .NET.Значение каждого параметра вставляется непосредственно в конечный SQL. Я настоятельно рекомендую вам попробовать. Просто запрос, который включает одну цитату, должен быть достаточным, чтобы дать вам представление о том, что происходит ... –

0

Вы делаете это правильно на самом деле. помните, что sql будет сгенерирован и выполнен, когда вы запросите данные.

вы можете сделать что-то вроде

var v = (from p in Context.User select p); 

if (txtLastName.Text.Lenght > 0) 
{ 
    v = (from p in v where p.LastName.Contains(txtLastName.Text) select p); 
} 

if (txtCity.Text.Lenght > 0) 
{ 
    v = (from p in v 
     join q in Context.City on p.City equals q.CityId 
     where q.CityName.Contains(txtCity.Text) select p); 
}