你好,我正在尝试构建一个表达式来通过主键获取通用实体并获取参数化的 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)
。值常量表达式不由查询翻译器参数化。您需要的是一个引用另一个表达式的属性或字段的表达式(其中could保持不变)。这基本上就是 C# 编译器为闭包发出的内容。
一种方法是实际使用 C# 编译器创建带有闭包的 lambda 表达式并获取主体:
Expression<Func<TKey>> keyValue = () => key;
var variableRef = key.Body;
(the variableRef
是你的替代品constantRef
)
另一种方法是使用匿名、元组或特定类类型来创建显式闭包实例并绑定相应的属性或字段。例如,对于匿名类型:
var variableRef = Expression.Property(Expression.Constant(new { key }), "key");
or with System.Tuple
:
var variableRef = Expression.Property(Expression.Constant(Tuple.Create(key)), "Item1");
实际的方法并不重要(我个人更喜欢第一个带有 lambda 的变体)——它们都会导致 EF Core 查询转换器创建参数。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)