【问题标题】:Can a LINQ to SQL IQueryable be unexpectedly evaluated?LINQ to SQL IQueryable 会被意外评估吗?
【发布时间】:2011-02-06 18:08:38
【问题描述】:

我正在编写一些代码,它采用 LINQ to SQL IQueryable<T> 并进一步添加动态生成的 Where 子句。例如这里是其中一种方法的骨架:

IQueryable<T> ApplyContains(IQueryable<T> source, string field, string value)
{
   Expression<Func<T, bool>> lambda;
   ... dynamically generate lambda for p => p.<field>.Contains(value) ...
   return source.Where(lambda);
}

我可能会将这些方法中的几个链接在一起,并以 Skip/Take 页面结束。

我是否正确地认为,当最终评估 IQueryable 时,如果 lambda 表达式中有任何内容无法转换为 SQL,则会引发异常?特别是我担心我可能会不小心做了一些事情,导致 IQueryable 提前评估,然后在内存中继续评估(从而拉入数千条记录)。

根据我读过的一些内容,我怀疑IQueryable 不会像这样提前评估。谁能确认一下?

【问题讨论】:

    标签: c# .net linq-to-sql iqueryable


    【解决方案1】:

    是的,如果部分表达式无法转换为 SQL,您的 IQueryable 可能会在运行时抛出错误是正确的。因此,我认为将查询放在业务层类(如数据服务或存储库)中是一个好主意,然后确保自动测试涵盖该查询。

    关于您的 Linq 表达式在意外时间求值,要记住的基本规则是,只要您在其上调用 foreach,您的表达式就会求值。这还包括在幕后调用 foreach 的方法,例如 ToList() 和 FirstOrDefault()。

    顺便说一句,判断一个方法是否要调用 foreach 并强制您的 lambda 评估的一种简单方法是检查该方法的返回值是否为 IQueryable。如果返回值是另一个 IQueryable,那么该方法可能只是添加到表达式中,而不是强制它进行评估。如果返回值是List&lt;T&gt;、匿名类型或任何看起来像数据而不是 IQueryable 的东西,那么该方法必须强制您的表达式进行评估以获取该数据。

    【讨论】:

    • 感谢您的提示。我确保将 IQueryables 保留在业务层中。通常,我的实体框架上下文对象只有一次调用业务层的生命周期 - 因此,如果超出该层,则无法评估 IQueryable。
    【解决方案2】:

    你的想法是正确的。

    只要您在 Where 子句中传递 IQueryable 和 Expression,它就不会被意外评估。

    此外,以“To”开头的扩展方法将导致评估(即 ToList()、ToArray())。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-21
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-19
      • 2014-12-11
      相关资源
      最近更新 更多