【问题标题】:is it possible to use a range variable from a linq (query syntax) as a parameter?是否可以使用 linq(查询语法)中的范围变量作为参数?
【发布时间】:2017-10-17 19:26:32
【问题描述】:

我正在尝试使用来自 linq 查询的范围变量作为参数;

简单的东西;

private static Expression<Func<context.Table1, bool>> funstuff(context.Table2 data)
{
    return x => true;
}

使用它就像另一个简单的例子,交叉连接;

var fun = from table2 in context.Table2
          from table1 in context.Table1.Where(funstuff(table2))
          select table1;

var f = fun.ToList();

我收到了这个错误;

从范围“”引用的“context.Table2”类型的变量“table2”, 但没有定义

实体框架6下是否可以使用范围变量作为参数?

编辑

context是实体框架的dbcontext

这个确切的代码确实有效;

var fun = from table2 in context.Table2
          from table1 in context.Table1.Where(x => table2.Id == 1)
          select table1;

var f = fun.ToList();

这不起作用;

private static Expression<Func<context.Table1, bool>> funstuff(context.Table2 data)
{
    return x => data.Id == 1;
}



var fun = from table2 in context.Table2
          from table1 in context.Table1.Where(funstuff(table2))
          select table1;

var f = fun.ToList();

我期待它会起作用。

【问题讨论】:

    标签: c# linq entity-framework-6


    【解决方案1】:

    我假设您的contextDbContext

    虽然大部分功能都差不多,但QueryableEnumerable还是有区别的。

    IEnumerable 对象包含所有代码以枚举位于本地内存中的集合中的对象。 IEnumerable 对象可以在枚举局部函数时使用它们。

    可查询枚举旨在在其他处理器上执行。 IQueryable 对象包含一个表达式,该表达式可以转换为其他处理器可以理解的格式。

    这个翻译不在Expression中,而是在IQueryable的另一个属性中:ProviderProvider 知道Expression 将在哪种类型的机器上执行。根据请求,Provider 将把这个表达式翻译(编译)成本机可以理解的格式,并将翻译发送到本机。

    对象context.Table2 实现IQueryableIQueryable 中的 Provider 知道如何将查询转换为 SQL。 SQL 不知道您的任何个人功能,例如funstuff,因此Provider 不知道如何将其转换为 SQL。事实上,一个 DbSet 甚至不支持所有类型的 LINQ 方法。

    MSDN: Supported and Unsupported LINQ Methods (LINQ to Entities)

    因此,只要您的语句是 IQueryable,您就不能调用任何本地函数。

    如果调用本地函数真的很重要,您可以将它们作为IEnumerable 执行。您可以使用函数AsEnumerable 执行此操作。这会将AsEnumerable 的输入数据带到本地内存。之后,您可以调用所有本地函数,就好像您的查询是 IEnumerable

    但是存在性能风险:如果输入是数以千计的对象,最终您只会得到几个对象,那么将所有这些信息都带到本地内存是一种浪费。

    结论:在调用AsEnumerable 之前,尝试将传输到本地内存的数据限制为最终结果所需的大小。之后你可以调用任何你想要的本地函数。

    【讨论】:

    • 查看我的编辑以了解更多(重要)细节...我昨天忘记写了。有了这些额外信息,您的答案仍然有效吗?
    • "因此,只要您的语句是 IQueryable,您就不能调用任何本地函数。" - 那不是真的。如果问题中的funstuff 不接受任何参数,或者您在那里传递常量参数(如外部Error 实例) - EF 提供程序将调用它并使用返回的Expression
    • 你确定吗?我可以在查询中调用 Rnd.Next() 吗?像 DbSet.MyItems.Where(item => item.Id == rnd.Next()).ToList()?它给了我一个 NotSupportedException “LINQ to Entities 无法识别方法 'Random.Next() 并且此方法无法转换为存储表达式'
    • 不,我不是指任何地方的任何方法。但是,如果可能,EF 将调用类似问题的方法(返回表达式并传递给“内部”Where 子句的方法)。例如ctx.Table2.SelectMany(table2 =&gt; ctx.Table1.Where(funstuff()));。请注意,我不是指在分析查询之前调用的方法。 OP 中的方法将由 EF 分析器查询分析期间调用。
    【解决方案2】:

    你不能这样做。考虑 Entity Framework 分析您的 LINQ 查询以将其转换为 SQL 查询。它一直分析到funstuff(table2) 呼叫。它认为这是一个它不知道的方法调用表达式(所以不像SqlFunctions.GetDate())。好的,现在EF分析器需要调用这个方法来获取表达式。如果方法没有参数或其参数已知 - 调用它没问题。但是这个方法参数代表查询参数table2。在分析表达式时它没有定义的值。在 SQL 查询执行期间它只会有一个值(它们的范围)。那时,在 SQL Server 上,当然不能使用该范围内的每个值调用您的方法。所以查询分析器绝对没有办法将您的查询转换为 SQL 并失败。

    【讨论】:

    • 查看我的编辑以了解更多(重要)细节...我昨天忘记写了。有了这些额外信息,您的答案仍然有效吗?
    • @Fredou 是的,我认为这是实体框架 DbContext(我实际上是从“考虑实体框架...”开始回答),所以信息仍然有效。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    • 1970-01-01
    相关资源
    最近更新 更多