使用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 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查询)。
你对IQueryable是正确的。 至于IEnumerable,它会在分配IEnumerable用户后立即命中数据库。
在您提供的示例中使用Linq Extensions与语法之间没有真正的区别。 有时候一个或另一个会更方便(参见linq-extension-methods-vs-linq-syntax ),但IMO更多的是个人偏好。