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

Ras*_*sto 7 .net c# ienumerable entity-framework iqueryable

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

IQueryable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
Run Code Online (Sandbox Code Playgroud)

与...完全相同

IQueryable<User> users = db.UserSet;   
var users32YearsOld = from user in users where user.Age == 32 select user;
Run Code Online (Sandbox Code Playgroud)

因此,它们users32YearsOld不会在数据库中出现,直到它们被枚举为循环等.(希望我能正确理解这一点).

但是,到底是怎么回事,如果我不掩盖这样的事情发生ObjectSetIQueryable,但作为IEnumerable?那么它的类型是IEnumerable什么?

IEnumerable<User> users = db.UserSet;
var users32YearsOld = users.Where(user => user.Age == 32);
Run Code Online (Sandbox Code Playgroud)

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

IEnumerable<User> users = db.UserSet;
var users32YearsOld = from user in users where user.Age == 32 select user;
Run Code Online (Sandbox Code Playgroud)

谢谢

Lad*_*nka 12

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

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

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

[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(); 
}
Run Code Online (Sandbox Code Playgroud)


Jes*_*per 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");
Run Code Online (Sandbox Code Playgroud)

如果你使用usersEnumerable,当你开始枚举它时,两个Wheres将按顺序运行; 首先,ObjectSet将获取所有对象,对象将被过滤到32岁的对象,然后这些将被过滤到名称以G开头的那些对象.

如果你使用usersQueryable,那么两个Wheres将返回将累积选择标准的新对象,当你开始枚举它时,它会将所有条件转换为查询.这会产生显着的差异.

通常,您不必担心,因为您要么声明var usersObjectSet 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查询).