您好,我正在尝试构建一个表达式以通过其主键获取通用实体并获取参数化的 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/