Linq: Dynamic Query Contruction: запрос перемещается на клиентскую сторону - PullRequest
1 голос
/ 24 сентября 2010

Я с большим интересом следил за разговором здесь:

Построение запроса с использованием Linq, а не строк SQL

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

С этой целью я создал метод Extension, addWhere, который выглядит следующим образом:

static public IQueryable<TResult> addWhere<TResult>(this IQueryable<TResult> query, string columnName, string value)
{
    var providerType = query.Provider.GetType();
    // Find the specific type parameter (the T in IQueryable<T>)
    var iqueryableT = providerType.FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
    var tableType = iqueryableT.GetGenericArguments()[0];
    var tableName = tableType.Name;
    var tableParam = Expression.Parameter(tableType, tableName);
    var columnExpression = Expression.Equal(
        Expression.Property(tableParam, columnName),
        Expression.Constant(value));
    var predicate = Expression.Lambda(columnExpression, tableParam);
    var function = (Func<TResult, Boolean>)predicate.Compile();
    var whereRes = query.Where(function);
    var newquery = whereRes.AsQueryable();
    return newquery;
}

[спасибо Timwi за основу этого кода]

Что функционально, работает.

Я могу позвонить:

query = query.addWhere("CurUnitType", "ML 15521.1");

, и это функционально эквивалентно:

query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));

, то есть возвращенные строкито же самое.

Однако я начал смотреть журнал sql и заметил строку:

query = query.Where(l => l.CurUnitType.Equals("ML 15521.1"));

Сгенерированный запрос:

SELECT (A bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]
WHERE [t0].[CurUnitType] = @p0

, тогда как когдаЯ использую строку

query = query.addWhere("CurUnitType", "ML 15521.1");

Сгенерированный запрос:

SELECT (the same bunch of columns)
FROM [dbo].[ObjCurLocView] AS [t0]

Итак, сравнение теперь происходит на стороне клиента, а не добавляется в sql.

Очевидно, это не так уж и жарко.

Если честно, я в основном вырезал и вставлял addWhere coде из примера Тимви (немного другой), поэтому некоторые из них у меня над головой.Мне интересно, есть ли какие-либо корректировки, которые я могу внести в этот код, поэтому выражение преобразуется в оператор SQL, а не определяется на стороне клиента

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

Приветствия.

1 Ответ

1 голос
/ 24 сентября 2010

Большая проблема в том, что вы преобразуете дерево выражений в делегат.Посмотрите на подпись Queryable.Where - она ​​выражается в деревьях выражений, а не в делегатах.Таким образом, вы на самом деле звоните Enumerable.Where.Вот почему вам нужно позвонить AsQueryable после этого - но здесь недостаточно магии.На самом деле это не возвращает его обратно к земле "просто деревьев выражений", потому что там все еще есть делегат.Теперь обернуто в дереве выражений, но вы потеряли детали того, что происходит внутри.

Я подозреваю, что вы хотите это:

var predicate = Expression.Lambda<Func<TResult, Boolean>>
      (columnExpression, tableParam);
return query.Where(predicate);

Я с готовностью признаю, что я не читал остальную часть вашего кода, поэтому могут происходить и другие вещи ... но это ключевой момент.Вам нужно строго типизированное дерево выражений (отсюда вызов универсальной формы Expression.Lambda), которую вы затем можете передать в Queryable.Where.Дайте ему шанс:)

...