使用扩展方法查询 IEnumerable 是否等同于使用 IQueryable?
Would using an extension method to query an IEnumerable be equivalent to using IQueryable?
我了解 IQueryable 和 IEnumerable 之间的主要区别。 IQueryable 在数据库中执行查询并 returns 过滤结果,而 IEnumerable 将完整的结果集带入内存并在那里执行过滤查询。
我不认为使用扩展方法查询变量的初始赋值会导致它像 IQueryable 一样在数据库中执行,但我只是想确定一下。
这段代码会导致从数据库中返回People的完整结果集,然后在内存中完成过滤:
(上下文中的人 属性 是 DbSet 类型)
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
尽管我在将项目分配给我的变量之前将下面的过滤添加为扩展方法,但我假设这段代码应该以与上面的代码相同的方式工作,并将完整的结果集返回到内存中在过滤之前,对吗?
Person person = context.People.Where(x => x.FirstName == "John");
编辑:
感谢大家的回复。我修改了代码示例以显示我的意思(删除了第二段代码中的 IEnumerable)。
此外,需要说明的是,context.People 是 DbSet 类型,它同时实现了 IQueryable 和 IEnumerable。所以我实际上不确定调用了哪个 .Where 方法。 IntelliSense 告诉我它是 IQueryable 版本,但这可信吗?直接使用上下文的 DbSet 时是否总是这种情况?
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
... 将执行 IEnumerable<T>.Where 方法扩展,它接受一个 Func<TSource, bool> predicate
参数,强制在内存中进行过滤。
相比之下...
IEnumerable<Person> people = context.People.Where(x => x.FirstName == "John");
...将执行 IQueryable<T>.Where 方法扩展,它接受 Expression<Func<TSource, bool>> predicate
参数。请注意,这是一个表达式,而不是委托,它允许它将 where
条件转换为数据库条件。
因此,调用哪种扩展方法确实会有所不同。
IQueryable 适用于表达式。它实际上是一个查询构建器,无需执行任何操作即可累积有关查询的信息……直到您需要从中获取值的那一刻,时间:
- 根据目标语言(例如SQL)累积的表达式生成查询
- 执行查询,通常在数据库上,
- 结果被转换回 C# 对象。
IEnumerable 扩展适用于预编译函数。当你需要它的值时:
- 执行这些函数中的 C# 代码。
这两者很容易混淆,因为:
- 两者都有名称相似的扩展函数,
- 表达式和函数的 lambda 语法相同 - 因此您无法区分它们,
使用 "var" 声明变量会删除数据类型(通常是关于正在使用哪个接口的唯一线索)。
IQueryable<int> a;
IEnumerable<int> b;
int x1 = a.FirstOrDefault(i => i > 10); // Expression passed in
int x2 = b.FirstOrDefault(i => i > 10); // Function passed in
具有相同名称的扩展方法通常做同样的事情(因为它们是那样写的)但有时它们不会。
所以答案是:不,它们不等价。
我了解 IQueryable 和 IEnumerable 之间的主要区别。 IQueryable 在数据库中执行查询并 returns 过滤结果,而 IEnumerable 将完整的结果集带入内存并在那里执行过滤查询。
我不认为使用扩展方法查询变量的初始赋值会导致它像 IQueryable 一样在数据库中执行,但我只是想确定一下。
这段代码会导致从数据库中返回People的完整结果集,然后在内存中完成过滤:
(上下文中的人 属性 是 DbSet 类型)
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
尽管我在将项目分配给我的变量之前将下面的过滤添加为扩展方法,但我假设这段代码应该以与上面的代码相同的方式工作,并将完整的结果集返回到内存中在过滤之前,对吗?
Person person = context.People.Where(x => x.FirstName == "John");
编辑:
感谢大家的回复。我修改了代码示例以显示我的意思(删除了第二段代码中的 IEnumerable)。
此外,需要说明的是,context.People 是 DbSet 类型,它同时实现了 IQueryable 和 IEnumerable。所以我实际上不确定调用了哪个 .Where 方法。 IntelliSense 告诉我它是 IQueryable 版本,但这可信吗?直接使用上下文的 DbSet 时是否总是这种情况?
IEnumerable<Person> people = context.People;
Person person = people.Where(x => x.FirstName == "John");
... 将执行 IEnumerable<T>.Where 方法扩展,它接受一个 Func<TSource, bool> predicate
参数,强制在内存中进行过滤。
相比之下...
IEnumerable<Person> people = context.People.Where(x => x.FirstName == "John");
...将执行 IQueryable<T>.Where 方法扩展,它接受 Expression<Func<TSource, bool>> predicate
参数。请注意,这是一个表达式,而不是委托,它允许它将 where
条件转换为数据库条件。
因此,调用哪种扩展方法确实会有所不同。
IQueryable
- 根据目标语言(例如SQL)累积的表达式生成查询
- 执行查询,通常在数据库上,
- 结果被转换回 C# 对象。
IEnumerable
- 执行这些函数中的 C# 代码。
这两者很容易混淆,因为:
- 两者都有名称相似的扩展函数,
- 表达式和函数的 lambda 语法相同 - 因此您无法区分它们,
使用 "var" 声明变量会删除数据类型(通常是关于正在使用哪个接口的唯一线索)。
IQueryable<int> a; IEnumerable<int> b; int x1 = a.FirstOrDefault(i => i > 10); // Expression passed in int x2 = b.FirstOrDefault(i => i > 10); // Function passed in
具有相同名称的扩展方法通常做同样的事情(因为它们是那样写的)但有时它们不会。
所以答案是:不,它们不等价。