Building a parameterized EntityFramework Core Expression

时间:2019-01-07 13:55:04

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

Hi, I'm trying to build an Expression to get a generic entity by its primary key and getting a parameterized sql query.

Currently I can get the correct WHERE query, but it isn't parameterized.

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);
}

This results in the following query: SELECT e.\"Id\", e.\"Name\" \r\n FROM \"People\" AS e\r\nWHERE e.\"Id\" = 1\r\nLIMIT 2, instead of the wanted: SELECT e.\"Id\", e.\"Name\" \r\n FROM \"People\" AS e\r\nWHERE e.\"Id\" = @__s_0\r\nLIMIT 2

1 个答案:

答案 0 :(得分:4)

这是因为Session_End。值常量表达式未由查询转换器参数化。您需要的是一个引用另一个表达式的属性或字段的表达式(可以为常数)。基本上,这就是C#编译器发出的用于关闭的内容。

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

Expression.Constant(key)

({Expression<Func<TKey>> keyValue = () => key; var variableRef = key.Body; 代替了您的variableRef

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

constantRef

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

System.Tuple

实际方法并不重要(我个人更喜欢使用lambda的第一个变体)-所有这些都会导致EF Core查询翻译器创建参数。