Динамически создавать запросы LINQ - принудительно использовать sp_executesql вместо необработанного запроса - PullRequest
0 голосов
/ 06 июля 2018

Мне нужно строить запросы динамически (классы сущностей имеют более 30 свойств, и я хочу избежать нескольких операторов if). Я решил это с помощью дерева отражений и выражений (итерация по свойствам и добавление предиката, если указаны некоторые критерии поиска). Проблема в том, что он генерирует сырой SQL-скрипт.

Пример

SELECT 
    [Extent1].[ProductId] AS [ProductId], 
    [Extent1].[ManufacturerId] AS [ManufacturerId], 
    [Extent1].[Title] AS [Title]
    FROM [dbo].[Products] AS [Extent1]
    WHERE 3 = [Extent1].[ManufacturerId]

Мне нужно получить запрос, используя процедуру sp_executesql (возобновление того же плана выполнения запроса).

exec sp_executesql N'SELECT 
    [Extent1].[ProductId] AS [ProductId], 
    [Extent1].[ManufacturerId] AS [ManufacturerId], 
    [Extent1].[Title] AS [Title]
    FROM [dbo].[Products] AS [Extent1]
    WHERE [Extent1].[ManufacturerId] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=3

Оказалось, проблема в следующем методе. Он использует Expression.Constant для создания объекта Expression. Я не знаю, чем мне его заменить.

public static Expression<Func<TItem, bool>> PropertyEqual<TItem, TValue>(
    this PropertyInfo property, TValue value)
{
    var param = Expression.Parameter(typeof(TItem));
    var body = Expression.Equal(Expression.Property(param, property),
        Expression.Constant(value, typeof(TValue)));
    return Expression.Lambda<Func<TItem, bool>>(body, param);
}

Как мне решить проблему?

1 Ответ

0 голосов
/ 06 июля 2018

Чтобы позволить EF использовать параметр вместо постоянного значения, вам нужно ввести замыкание (аналогично тому, что компилятор C # делает для выражений времени компиляции).

Один из способов - создать анонимный тип и связать его свойство:

var closure = new { value };
var body = Expression.Equal(Expression.Property(param, property),
    Expression.Property(Expression.Constant(closure), "value"));

Другой способ - использовать компилятор C # для создания выражения замыкания и связывания его тела:

Expression<Func<TValue>> closure = () => value;
var body = Expression.Equal(Expression.Property(param, property),
    closure.Body);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...