c# - 构建参数化的 EntityFramework 核心表达式

标签 c# asp.net entity-framework-core

您好,我正在尝试构建一个表达式以通过其主键获取通用实体并获取参数化的 sql 查询。

目前我可以得到正确的 WHERE 查询,但它没有参数化。

public async Task<TDbo> Get(TKey key, Expression<Func<TEntity, TKey>> keySelector)
{
    var propertyRef = keySelector.Body;
    var parameter = keySelector.Parameters[0];
    var constantRef = Expression.Constant(key);
    var equals = Expression.Equal(propertyRef, constantRef);
    var comparer = Expression.Lambda<Func<TEntity, bool>>(equals, parameter);

    return await _context.Set<TDbo>().SingleOrDefaultAsync(comparer);
}

这会产生以下查询: SELECT e.\"Id\", e.\"Name\"\r\n FROM\"People\"AS e\r\nWHERE e.\"Id\"= 1\r\nLIMIT 2, 而不是想要的: SELECT e.\"Id\", e.\"Name\"\r\n FROM\"People\"AS e\r\nWHERE e.\"Id\"= @__s_0\r\nLIMIT 2

最佳答案

这是因为 Expression.Constant(key)。查询翻译器不参数化值常量表达式。您需要的是一个引用另一个表达式(可以 是常量)的属性或字段的表达式。这基本上就是 C# 编译器为闭包发出的内容。

一种方法是实际使用 C# 编译器创建带闭包的 lambda 表达式并获取主体:

Expression<Func<TKey>> keyValue = () => key;
var variableRef = key.Body;

(variableRef 是您的 constantRef 的替代品)

另一种方法是使用匿名、元组或特定类类型创建显式闭包实例并绑定(bind)相应的属性或字段。例如,匿名类型:

var variableRef = Expression.Property(Expression.Constant(new { key }), "key");

或使用System.Tuple:

var variableRef = Expression.Property(Expression.Constant(Tuple.Create(key)), "Item1");

实际的方法并不重要(我个人更喜欢第一个带有 lambda 的变体)——它们都会导致由 EF Core 查询翻译器创建参数。

关于c# - 构建参数化的 EntityFramework 核心表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54803889/

相关文章:

asp.net - 将 WebGrease 升级到版本 1.3.0 仅在生产服务器上导致错误

ASP.NET 中的 mysql 参数化查询

c# - 实体类型上的导航还没有被添加到模型中,或者被忽略,或者 entityType 被忽略

asp.net-core - EntityFrameworkCore 上的 scaffold-dbcontext basepath 异常

C# 高效的图像绘制和移动

C# 将 OrderDate 与变量进行比较

c# - 生成用户特定的 1 次优惠券代码

C# DynamicPDF 合并导致 "Index out of bounds"错误

c# - 首先是ASP.NET mvc数据库教程

c# - 将 EF Core 列/字段指定为只读