急切Include函数是否调用内存中的数据

本文关键字:数据 内存 调用 Include 函数 是否 急切 | 更新日期: 2023-09-27 18:01:22

我正在阅读这个答案,我意识到我不清楚急切加载如何在IQueryable的内存生命周期中工作。

假设您有db.Customers.Include("Orders"),它生成如下的对象图:

Customer
   Order
   Order
   Order

如果你不枚举从一个Include返回它加载数据在内存中吗?

也就是说,

IQueryable<Customer> customersWithOrders = db.Customers.Include("Orders");

暗示Customer集合(和他的Orders)已经被热切包含的Orders带入内存?或者,"急切"是否意味着如果/当枚举Customer集合时,订单也将被带入内存?

急切Include函数是否调用内存中的数据

这里发生了两件事。首先,在需要执行查询的某些操作完成之前,不会向数据库提交查询。例如,如果您要这样做:

var foos = db.Foos.Where(...);

实际上还没有发出任何查询。但是,如果您要这样做:

foreach (var foo in foos)
{
    ...
}

然后,将查询发送到数据库。其他会导致查询被执行的事情是调用ToList()Count()等。基本上,每当需要实际数据时,实体框架才会发送查询。

然后,有一个完全不同的概念,即急切加载和延迟加载。这是关于相关的项,基本上是关于实体框架是否应该发出一个或多个连接作为查询的一部分。通过使用Include(),您指示实体框架为该关系发出连接。同样,在计算(迭代、枚举、计数等)之前不会发出查询,但是当您对其进行计算时,您包含的实体集和相关实体都将立即被拉出。

如果你选择不包含一个关系,那么你就回退到延迟加载,这意味着除非你以某种方式访问它,否则这个关系将不会被具体化。这在某些方面类似于初始查询的工作方式。相关的项只在实际需要数据的地方获取;否则不会发出任何查询。但是,这将是一个完全独立的查询。

无论长短,你只需要注意你需要什么数据,什么时候需要。如果您打算使用相关实体,那么您应该在查询求值之前包含这些,但无论哪种方式,查询只会在它所代表的数据是必要的时候发送。

即时加载只修改底层查询。这也是为什么你可以链接多个Include()调用(以及其他依赖于LINQ延迟执行特性的LINQ调用)。

只有在枚举时才会从数据源显式地请求数据。

更新(根据@Ehsan Sajjad评论):

使用Lazy-Loading,即使查询已经物化(例如使用foreachToList()), navigation-property(在本例中为Order)只会在访问它时从数据源请求。