【问题标题】:Building a parameterized EntityFramework Core Expression构建参数化的 EntityFramework 核心表达式
【发布时间】:2019-01-07 13:55:04
【问题描述】:

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

【问题讨论】:

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


    【解决方案1】:

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

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

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

    variableRef 是您的 constantRef 的替代品)

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

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

    System.Tuple:

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

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

    【讨论】:

    • 有没有办法在没有TKey 的情况下做到这一点?我确实有一个 IKey 代表 TDbo 的主键。
    • 如果您的意思是 FindAsync 方法,是的。这是可能的。
    • FindAsync 需要直接在 DbSet 上工作(据我了解),而我需要进行一些查询(即Include()'s),这会返回一个 IQueryable
    • @mixandmatch 我的意思类似于FindAsync 方法参数以及它如何使用IKey 属性动态构建谓词表达式。
    猜你喜欢
    • 1970-01-01
    • 2020-03-27
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-18
    • 1970-01-01
    相关资源
    最近更新 更多