使用IEnumerable和IQueryable作为一种ObjectSet时的差异

据我所知,当我在IQueryable上使用LINQ扩展方法(使用lambda表达式语法)时,它们在ObjectSet的事实实例中被转换为LINQ to SQL查询。 我的意思是那个命令

 IQueryable users = db.UserSet; var users32YearsOld = users.Where(user => user.Age == 32); 

与…完全相同

 IQueryable users = db.UserSet; var users32YearsOld = from user in users where user.Age == 32 select user; 

因此,它们中没有它们会访问数据库,直到他们的users32YearsOld被枚举为for循环或类似。 (希望我理解正确)。

但是如果我不将ObjectSet屏蔽为IQueryable但是IEnumerable什么呢? 那么如果它的类型是IEnumerable

 IEnumerable users = db.UserSet; var users32YearsOld = users.Where(user => user.Age == 32); 

它会立即打到数据库(如果是这样的话,那么?在第一行或第二行)? 或者它是否会像上一个命令一样,在枚举users32YearsOld之前不会命中数据库? 如果我使用以下代码会有什么不同吗?

 IEnumerable users = db.UserSet; var users32YearsOld = from user in users where user.Age == 32 select user; 

谢谢

取消我的答案,因为我刚测试它,它完全按照我的描述工作:

由于没有枚举,所有提到的查询都不会访问数据库。 IQueryable查询和IEnumerable查询之间的区别在于,在IQueryable的情况下,过滤将在数据库服务器上执行,而在IEnumerable的情况下,所有对象将从数据库加载到内存,过滤将在.NET中完成代码(linq-to-objects)。 你可以想象这通常是性能杀手。

我在我的项目中编写了简单的测试:

 [TestMethod] public void Test() { // ObjectQuery converted ot IEnumerable IEnumerable departmetns = CreateUnitOfWork().GetRepository().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(); } 

这是一个简单的解释:

 IEnumerable usersEnumerable = db.UserSet; IQueryable 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 usersObjectSet users ,这意味着C#将知道您有兴趣调用ObjectSet上可用的最具体的方法,并且IQueryable查询运算符方法( WhereSelect ,…)比IEnumerable方法更具体。 但是,如果将对象传递给采用IEnumerable参数的方法,则最终可能会调用错误的方法。

您还可以使用AsEnumerable()AsQueryable()方法开始使用其他方法,从而使用这种方式对您有利。 例如, var groupedPeople = users.Where(user => user.Age > 15).AsEnumerable().GroupBy(user => user.Age); 将使用数据库查询拉下正确的用户,然后在本地对对象进行分组。

正如其他人所说,值得重复的是,在你开始枚举序列之前没有任何事情发生(使用foreach )。 您现在应该理解为什么它不能是任何其他方式:如果一次检索所有结果,则无法构建查询以转换为更有效的查询(如SQL查询)。

你对IQueryable是正确的。 至于IEnumerable,它会在分配IEnumerable用户后立即命中数据库。

在您提供的示例中使用Linq Extensions与语法之间没有真正的区别。 有时候一个或另一个会更方便(参见linq-extension-methods-vs-linq-syntax ),但IMO更多的是个人偏好。