我对IsLoaded的理解是否正确?

时间:2011-12-15 20:02:14

标签: c# .net entity-framework ef-code-first change-tracking

以下是一些代码以及基于在LINQPad中玩游戏的假设。任何人都可以确认这是延迟加载是如何工作的,并且可能提供任何额外的洞察/链接,以便我能理解它是如何在后端工作的?提前谢谢!

// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. 检索一些记录(查询数据库)。
  2. 检索恰好是record的外键属性的记录,而不使用record.ForeignKey之类的延迟加载来检索它(查询数据库)。
  3. 获取record实体的详细信息。
  4. 这是我不确定的部分。在我的测试中,它输出true。我猜测IsLoaded并不知道record.ForeignKey当前是否有值,但知道record.ForeignKey已根据其知识在上下文中被跟踪record.ForeignKeyId以及已建立的关系。
  5. db似乎没有在这里被击中,我认为它是出于同样的原因IsLoaded在4中返回true。它知道它跟踪{{ 1}}对象已经存在,因此它知道它不必进行延迟加载。
  6. 修改:我试图解决的实际问题可以说明如下:

    foreignKey

2 个答案:

答案 0 :(得分:2)

当您从数据库加载实体或将其附加到上下文时,EF会根据主键和外键值自动修复关系(导航属性)。

在两个代码段中,您已加载record,其中ForeignKeyTable具有外键。上下文知道这个值。 (如果你在你的模型中暴露了外键,那顺便也没关系。它总是被加载,你的模型中也没有FK属性。你可以在看SQL查询时看到这个。)

在这两种情况下,您都会将ForeignKey实体附加到上下文中,该上下文具有上下文已知的record.ForeignKeyId值作为主键。因此,EF会将导航属性record.ForeignKey设置为此附加的ForeignKey实体。

显然IsLoaded没有告诉你实体是否附加到上下文,因为在两个示例中它都被附加但是一个返回true而另一个false。它也没有告诉你record.ForeignKeyId是否引用了一个实体,因为在这两个例子中都是如此。

它显然只告诉你实体已经真正从数据库加载(并且不仅仅是手动附加)(Intellisense也说IsLoaded)。这是你的第一个和第二个例子之间的唯一区别。

似乎延迟加载不仅受IsLoaded标志控制。如果将导航属性的实体附加到上下文,则虽然IsLoadedfalse,但不会再进行延迟加载。

如果第二个代码段中的最后一行实际上会触发延迟加载,会发生什么?正在加载的ForeignKey对象必须与您已附加的ForeignKey对象具有相同的密钥(因为record将此值作为FK属性ForeignKeyId)。但是因为没有两个具有相同键的对象可以附加到上下文,所以它必须是同一个对象。但是没有必要加载它,因为这样的对象已经在内存中并附加了。

答案 1 :(得分:1)

// Step 1.
var record = context.MyTable.First();

// Step 2.
var foreignKey = ForeignKeyTable.Where(x => x.Id == record.ForeignKeyId).Single();

// Step 3.
var entry = context.Entry(record);

// Step 4.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Step 5.
trace(record.ForeignKey.SomeProperty);
  1. 检索一些记录(查询数据库)。 是的,结果记录附加到DbContext。
  2. 检索恰好是记录的外键属性的记录,而不使用像record.ForeignKey这样的延迟加载来检索它(查询数据库)。 是。如果你想在#1中急切加载外键,你就会使用context.MyTable.Include(m => m.ForeignKey).First();这将与1个查询中的fk一起检索记录。
  3. 获取记录实体的详细信息。 有点......它是与DbContext相关的实体的详细信息(附加/删除/加载/等)
  4. 这是我不确定的部分。在我的测试中它输出true。我猜IsLoaded不知道record.ForeignKey当前是否有值,但是知道record.ForeignKey已经基于它对record.ForeignKeyId的知识以及已经建立的关系在上下文中被跟踪。 这意味着DbContext不需要运行另一个查询来加载外键的数据。如果执行record.ForeignKey,则数据已经存在,并且不需要额外访问数据库
  5. db似乎没有在这里被击中,我认为它是出于同样的原因IsLoaded在4中返回true。它知道它已经跟踪了foreignKey对象,所以它知道它不必做懒惰加载。 已在第2步中加载了权利,因此无法从数据库中获取该权限。
  6. 问题修改后更新

    根据EF,IDbSet上的.Attach方法:

    将给定实体附加到集合下的上下文中。也就是说,实体被置于Unchanged状态的上下文中,就像从数据库中读取它一样。