为什么我应该使用 .Include(...) 来包含导航属性?

Why should I use `.Include(...)` to include navigation properties?

当视图对所有导航属性具有可见性时,我为什么要放置 .Include(...)

  1. 动作 1

     public ActionResult Included(){
         var models = db.Money.Include(m=>m.Rate);
         return View(models);
     }
    
  2. 动作 2

     public ActionResult UnIncluded(){
         var models = db.Money;
         return View(models);
     }
    

在这两个视图中我可能得到的金额如下

   @Html.DisplayFor(model=>model.Rate.Amount)

那么,有什么区别呢? 这就是我们所说的延迟加载模式吗?

.Include 强制预先加载指定的 属性,而不是延迟加载,假设在您的应用程序中打开了延迟加载。因此,在您的第一个操作中, Rate 将立即从数据库中取回,而您的第二个操作则相反,在第二个操作中,只有在需要时(即,当您在页面上调用 model.Rate.Amount 时)。

您应该注意的一件事:如果您正在使用延迟加载,实际上您应该在控制器操作中使用 .Include 或使用 .ToList(),因为您可以可能 运行 遇到异常情况,因为您的控制器在 视图调用导航 属性 之前 处理了 DbContext 对象EF 返回数据库。所以上面的 Action1 可能是避免这种情况的更好方法。

Include 上的 MSDN post 可以找到 here

So, what is the difference? Is this what we know as lazy load mode?

是的。

假设您的 Money table 有 1000 行。还假设 Rate 是导航 属性,以下将执行 1001 个单独的 SQL 查询:

public ActionResult UnIncluded(){
     var models = db.Money;
     return View(models);
}
...
@Html.DisplayFor(model=>model.Rate.Amount)

为什么?上述操作将 return 只有 Money 数据显示到视图中。然后视图在遍历每个 Money 实例时,将延迟加载每个 .Rate 实例。这意味着 1000 个额外的 SQL 查询,每个查询对应集合中的每个 Money 项。

但是,下面只会执行 1 SQL 个查询:

public ActionResult Included(){
     var models = db.Money.Include(m=>m.Rate);
     return View(models);
 }
...
@Html.DisplayFor(model=>model.Rate.Amount)

为什么?上述操作将执行单个 SQL 查询,该查询在 MoneyRate table 之间执行 JOIN 以加载每个 Rate 的所有数据1000 Money 只需要一次数据库往返 。这称为预加载。

这是假设您启用了延迟加载,并且 Ratevirtual 导航 属性 on Money.