为什么.带有 Func 参数的 Where() 执行查询

本文关键字:执行 查询 Where 带有 Func 参数 为什么 | 更新日期: 2023-09-27 17:56:13

这是我的DataAccessLayer的工作原理:

 public Foo GetFooBy(Func<Foo, bool> filter)
 {
     var query = from item in this.DataService.FooSet select item;
     var where = query.Where(filter);
     var first = where.First();
     return first;
 }

我假设在调用 First() 时会运行查询,但它实际上是由 Where() 执行的。从MSDN中,我意识到.Where(Func) 是由枚举定义的扩展方法,所以它是有道理的,但我不明白它与调用有什么不同。Where() 带有 lambda 表达式。

一种非常简单的方法来确定.Where() 具体化的数据是检查查询的类型、位置和第一个的类型。

  1. 查询是 IQueryable,这意味着数据库中尚未发生任何内容
  2. 其中 IEnumerable,表示数据已具体化*
  3. 首先是阿福

调试和 SQL 跟踪还非常清楚地表明,数据是由 .其中()

编辑 : * 可能不正确,因为 IQueryable 实现了 IEnumerable

为什么.带有 Func 参数的 Where() 执行查询

Enumerable.WhereQueryable.Where 之间有一个非常重要的区别:

Enumerable.Where需要Func<T, bool>.

Queryable.Where需要Expression.

你的filter变量不是Expression,它是一个Func<T, bool>,因此编译器使用Enumerable.Where

然后发生的情况是,FOO表的所有行都传输到客户端,然后在内存中筛选。

正如其他人正确指出的那样,执行仍然发生在调用 First() .

更新:
您的 SQL 跟踪无法证明具体化发生在对 Where 的调用上。它只能证明Where的过滤没有在服务器端发生。原因在我上面的回答中得到了解释。

如何解决:
您可以通过更改方法以采用表达式来轻松解决此问题:

public Foo GetFooBy(Expression<Func<Foo, bool>> filter)
{
    var query = from item in this.DataService.FooSet select item;
    var where = query.Where(filter);
    var first = where.First();
    return first;
}

我假设查询将在调用First()时运行

这是一个正确的假设。

但它实际上是由Where()执行

这要么是错误的,要么您没有使用System.LinqWhere方法。

我不明白它与使用 lambda 表达式调用Where()有何不同。

不是。 好吧,除非您提供了 lambda,Queryable.Where将是执行的那个,但在这两种情况下,执行都会被推迟。


附带说明一下,可以将整个方法主体重写为:

return this.DataService.FooSet.First(filter);

它的行为会相同。