【问题标题】:Build LINQ queries dynamically - force using sp_executesql instead of raw query动态构建 LINQ 查询 - 强制使用 sp_executesql 而不是原始查询
【发布时间】:2018-07-06 10:11:36
【问题描述】:

我需要动态构建查询(实体类有 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);
}

我该如何解决这个问题?

【问题讨论】:

  • 表达式应该是等价的。也许这就是您使用它的方式...您使用的是什么.Where重载?
  • Where(this IQueryable source, Expression> predicate)

标签: c# entity-framework linq expression


【解决方案1】:

为了让 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多