EF:延迟加载,急切加载和"枚举可枚举"

Cyn*_*hia 19 entity-framework lazy-loading eager-loading entity-framework-4

我发现我对延迟加载等感到困惑.

首先,这两个陈述是否相同:

(1) Lazy loading:
_flaggedDates = context.FlaggedDates.Include("scheduledSchools")
.Include  ("interviews").Include("partialDayAvailableBlocks")
.Include("visit").Include("events");

(2) Eager loading:
_flaggedDates = context.FlaggedDates;
Run Code Online (Sandbox Code Playgroud)

换句话说,在(1)中,"包含"导致导航集合/属性与所请求的特定集合一起被加载,而不管您是否使用延迟加载......对吗?

在(2)中,语句将加载所有导航实体,即使您没有特别请求它们,因为您正在使用急切加载......对吗?

第二:即使您正在使用预先加载,在您"枚举可枚举"之前,数据实际上不会从数据库中下载,如下面的代码所示:

var dates = from d in _flaggedDates
            where d.dateID = 2
            select d;
foreach (FlaggedDate date in dates)
{
... etc.
}
Run Code Online (Sandbox Code Playgroud)

在foreach循环之前,数据实际上不会被下载("枚举")......对吗?换句话说,"var dates"行定义了查询,但直到foreach循环才执行查询.

鉴于(如果我的假设是正确的),渴望加载和延迟加载之间的真正区别是什么?似乎在任何一种情况下,数据在枚举之前都不会出现.我错过了什么吗?

(我的具体经验是代码优先,POCO开发,顺便说一句......虽然问题可能更普遍适用.)

Str*_*ior 17

您对(1)的描述是正确的,但它是Eager Loading而不是Lazy Loading的示例.

您对(2)的描述不正确.(2)在技术上根本不使用加载,但如果您尝试访问FlaggedDates上的任何非标量值,则将使用延迟加载.

在任何一种情况下,您都是正确的,在您尝试使用_flaggedDates"执行某些操作"之前,不会从数据存储中加载任何数据.但是,在每种情况下发生的情况都不同.

(1):预先加载:一旦你开始for循环,已指定将得到从数据库中抽取,并建成一个巨大的内存中的数据结构中的对象的每一个.这将是一项非常昂贵的操作,从您的数据库中提取大量数据.但是,它将全部发生在一个数据库往返中,执行单个SQL查询.

(2):延迟加载:当你的for循环开始时,它只会加载FlaggedDates对象.但是,如果访问for循环内的相关对象,则它们不会将这些对象加载到内存中.检索给定FlaggedDate的scheduledSchools将导致在任何一个新的数据库往返的第一次尝试检索的学校,或者是因为你的背景已被释放引发异常.既然你可以访问内部的scheduledSchools收集for循环,就必须为每一个您最初装在年初FlaggedDate一个新的数据库往返for循环.

回应评论

禁用延迟加载与启用Eager Loading不同.在这个例子中:

context.ContextOptions.LazyLoadingEnabled = false;
var schools = context.FlaggedDates.First().scheduledSchools;
Run Code Online (Sandbox Code Playgroud)

schools变量将包含一个空EntityCollection,因为我没有Include在原来的查询它们(FlaggedDates.First()),我禁用延迟加载,使得已经执行的初始查询后,他们无法加载.

你是正确的,因为where d.dateID == 2将意味着只有涉及到具体FlaggedDate对象的对象会在被拉动.但是,这取决于有多少个对象与该FlaggedDate,你仍然可以结束了一个大量的数据要超过该线的.这是由于EntityFramework构建其SQL查询的方式.SQL查询结果始终采用表格格式,这意味着每行必须具有相同的列数.对于每个scheduledSchool对象,结果集中至少需要有一行,并且因为每行必须包含至少一些每列的值,您最终会重复FlaggedDate对象上的每个标量值.因此,如果你有10个预定学校和10个与你的FlaggedDate相关的访谈,你最终会得到20行,每行包含FlaggedDate上的每个标量值.对于所有ScheduledSchool列,一半行将具有空值,而对于所有Interviews列,另一半将具有空值.

但是,如果你在你所包含的数据中"深入",那么这会变得非常糟糕.例如,如果每个ScheduledSchool有一个students属性,你包括在内,然后突然你就必须为每个ScheduledSchool每个学生一排,并在每个那些行,为学生ScheduledSchool每标值将包括(即使只有第一行的值最终被使用),以及原始FlaggedDate对象上的每个标量值.它可以快速加起来.

这很难以书面形式解释,但是如果你看一下从多个Includes 的查询中返回的实际数据,你会发现有很多重复的数据.您可以使用LinqPad查看EF代码生成的SQL查询.