据我所知,当我在IQueryable
的{{1}}上使用LINQ扩展方法(使用lambda表达式语法)时,它们被转换为LINQ to SQL查询。我的意思是那个命令
ObjectSet
与
完全相同IQueryable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
因此,在它们IQueryable<User> users = db.UserSet;
var users32YearsOld = from user in users where user.Age == 32 select user;
被枚举为循环之类的情况下,它们不会访问数据库。 (希望我能正确理解这一点)。
但如果我不将users32YearsOld
掩盖为ObjectSet
而将IQueryable
掩盖,会发生什么?如果它的类型是IEnumerable
?
IEnumerable
是否会立即打到数据库(如果是这样的话,那么?在第一行或第二行)?或者它是否会像上一个命令一样,在枚举IEnumerable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
之前不会命中数据库?如果我使用以下代码会有什么不同吗?
users32YearsOld
谢谢
答案 0 :(得分:12)
取消删除我的回答是因为我刚测试了它,它的工作原理与我描述完全相同:
由于没有枚举,所提到的查询都不会访问数据库。 IQueryable
查询和IEnumerable
查询之间的区别在于,在IQueryable
的情况下,过滤将在数据库服务器上执行,而在IEnumerable
的情况下,所有对象都将在从数据库加载到内存,过滤将在.NET代码(linq-to-objects)中完成。你可以想象这通常是性能杀手。
我在我的项目中编写了简单的测试:
[TestMethod]
public void Test()
{
// ObjectQuery<Department> converted ot IEnumerable<Department>
IEnumerable<Department> departmetns = CreateUnitOfWork().GetRepository<Department>().GetQuery();
// No query execution here - Enumerable has also deffered exection
var query = departmetns.Where(d => d.Id == 1);
// Queries ALL DEPARTMENTS here and executes First on the retrieved result set
var result = departmetns.First();
}
答案 1 :(得分:6)
这是一个简单的解释:
IEnumerable<User> usersEnumerable = db.UserSet;
IQueryable<User> usersQueryable = db.UserSet;
var users = /* one of usersEnumerable or usersQueryable */;
var age32StartsWithG = users.Where(user => user.Age == 32)
.Where(user => user.Name.StartsWith("G");
如果你使用usersEnumerable
,当你开始枚举它时,两个Where
将按顺序运行;首先ObjectSet
将获取所有对象,对象将被过滤到32岁的对象,然后这些对象将被过滤到名称以G开头的那些对象。
如果您使用usersQueryable
,则两个Where
将返回将会累积选择条件的新对象,当您开始对其进行枚举时,它会将所有条件转换为查询。这会产生显着的差异。
通常情况下,您无需担心,因为您在声明变量时会说var users
或ObjectSet users
,这意味着C#会知道您有兴趣调用最多ObjectSet
上可用的特定方法和IQueryable
查询运算符方法(Where
,Select
,...)比IEnumerable
方法更具体。但是,如果将对象传递给采用IEnumerable
参数的方法,则最终可能会调用错误的方法。
您还可以使用AsEnumerable()
和AsQueryable()
方法开始使用其他方法,以此方式发挥作用。例如,var groupedPeople = users.Where(user => user.Age > 15).AsEnumerable().GroupBy(user => user.Age);
将使用数据库查询拉下正确的用户,然后在本地对对象进行分组。
正如其他人所说,值得重复的是,在你开始枚举序列(使用foreach
)之前不会发生任何事情。您现在应该理解为什么它不能以任何其他方式:如果一次检索所有结果,则无法构建查询以转换为更有效的查询(如SQL查询)。
答案 2 :(得分:0)
你对IQueryable是正确的。至于IEnumerable,它会在分配IEnumerable用户后立即命中数据库。
在您提供的示例中使用Linq Extensions与语法之间没有真正的区别。有时候一个或另一个会更方便(见linq-extension-methods-vs-linq-syntax),但IMO更多的是个人偏好。
答案 3 :(得分:0)
The difference is that IEnumerable performs the filters if they are more, one at a time. For example, from 100 elements will output 20 by the first filter and then will filter second time the needed 10. It will make one query to the database but will download unnecessary data. Using IQueryable will download again with one query but only the required 10 items. The following link gives some excellent examples of how these queries work: https://filteredcode.wordpress.com/2016/04/29/ienumerable-vs-iqueryable-part-2-practical-questions/