以下是一些代码以及基于在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);
record
的外键属性的记录,而不使用record.ForeignKey
之类的延迟加载来检索它(查询数据库)。record
实体的详细信息。true
。我猜测IsLoaded并不知道record.ForeignKey
当前是否有值,但知道record.ForeignKey
已根据其知识在上下文中被跟踪record.ForeignKeyId
以及已建立的关系。IsLoaded
在4中返回true。它知道它跟踪{{ 1}}对象已经存在,因此它知道它不必进行延迟加载。修改:我试图解决的实际问题可以说明如下:
foreignKey
答案 0 :(得分:2)
当您从数据库加载实体或将其附加到上下文时,EF会根据主键和外键值自动修复关系(导航属性)。
在两个代码段中,您已加载record
,其中ForeignKeyTable
具有外键。上下文知道这个值。 (如果你在你的模型中暴露了外键,那顺便也没关系。它总是被加载,你的模型中也没有FK属性。你可以在看SQL查询时看到这个。)
在这两种情况下,您都会将ForeignKey
实体附加到上下文中,该上下文具有上下文已知的record.ForeignKeyId
值作为主键。因此,EF会将导航属性record.ForeignKey
设置为此附加的ForeignKey
实体。
显然IsLoaded
没有告诉你实体是否附加到上下文,因为在两个示例中它都被附加但是一个返回true
而另一个false
。它也没有告诉你record.ForeignKeyId
是否引用了一个实体,因为在这两个例子中都是如此。
它显然只告诉你实体已经真正从数据库加载(并且不仅仅是手动附加)(Intellisense也说IsLoaded
)。这是你的第一个和第二个例子之间的唯一区别。
似乎延迟加载不仅受IsLoaded
标志控制。如果将导航属性的实体附加到上下文,则虽然IsLoaded
为false
,但不会再进行延迟加载。
如果第二个代码段中的最后一行实际上会触发延迟加载,会发生什么?正在加载的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);
问题修改后更新
根据EF,IDbSet上的.Attach方法:
将给定实体附加到集合下的上下文中。也就是说,实体被置于Unchanged状态的上下文中,就像从数据库中读取它一样。