【问题标题】:Is my understanding of IsLoaded correct?我对 IsLoaded 的理解正确吗?
【发布时间】:2011-12-15 20:02:13
【问题描述】:

这是一些代码以及我基于在 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 的原因相同。它知道它已经在跟踪 foreignKey 对象,所以它知道它没有进行延迟加载。

编辑:我试图解决的实际问题可以这样说明:

var record = context.MyTable.First();

var foreignKey = new ForeignKey() { Id = record.ForeignKeyId, SomeProperty = 5 };
context.ForeignKeyTable.Attach(foreignKey);

var entry = context.Entry(record);

// Returns false.
trace(entry.Reference(x => x.ForeignKey).IsLoaded);

// Doesn't query for ForeignKey, so it must know it's `loaded` somehow, and
// gets SomeProperty from my new foreignKey object. What???
trace(record.ForeignKey.SomeProperty);

【问题讨论】:

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


    【解决方案1】:

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

    在两个代码 sn-ps 中,您都加载了 record,它有一个外键到您的 ForeignKeyTable。上下文知道这个值。 (顺便说一句,如果您在模型中公开了外键也没关系。它将始终被加载,而且您的模型中也没有 FK 属性。您可以在观看 SQL 查询时看到这一点。)

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

    显然IsLoaded 不会告诉您实体是否附加到上下文,因为在两个示例中它都已附加但一个返回true 而另一个返回false。它也不会告诉您record.ForeignKeyId 是否指的是一个实体,因为在两个示例中也是如此。

    它显然只是告诉您该实体确实是从数据库中加载的(不仅是手动附加的)(Intellisense 也提到了IsLoaded)。这是您的第一个和第二个示例之间的唯一区别。

    似乎延迟加载不仅由IsLoaded 标志控制。如果将导航属性的实体附加到上下文,则不会再发生延迟加载,尽管 IsLoadedfalse

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

    【讨论】:

    • 那么我是否不走运寻找一种快速的方法来做这样的事情:`entry.Reference(x => x.ForeignKey).ExistsInContext?我有点需要这个功能,但我不知道从哪里开始创建它。
    • @Ocelot20:你可以试试ctx.ForeignKeys.Local.Any(f => f.Id == 1)Local 提供有关上下文中未更改、修改和添加的实体的视图。或者你可以通过ctx.ChangeTracker.Entries()...。我想知道您为什么需要它,我认为这与您的问题无关。也许创建一个新问题,更关注该问题以及为什么需要这样的功能。
    【解决方案2】:
    // 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();这将检索记录以及 fk in 1 查询。
    3. 获取记录实体的详细信息。 有点......它是与 DbContext 相关的实体的详细信息(附加/删除/加载/等)
    4. 这是我不确定的部分。在我的测试中,它输出 true。我猜 IsLoaded 不知道 record.ForeignKey 当前是否有值,但知道 record.ForeignKey 已经根据它对 record.ForeignKeyId 的了解和已建立的关系在上下文中被跟踪。 这意味着 DbContext 不需要运行另一个查询来加载外键的数据。如果执行record.ForeignKey,数据已经存在了,不需要额外去db了
    5. 这里似乎没有命中 db,我认为这与 IsLoaded 在 4 中返回 true 的原因相同。它知道它已经在跟踪 foreignKey 对象,所以它知道它不必做惰性加载。 实体已在第 2 步中加载,因此无需额外的行程即可从数据库中获取它。

    问题编辑后更新

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

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

    【讨论】:

    • 我知道如果我使用 Include 它将与外键一起加载记录。我更想知道它如何知道它已经在第 4 步中加载了。我在我的应用程序中运行了类似的测试,第 4 步返回 false。 foreignKey 的等效项是以不会创建对象代理的方式加载的,所以我想知道它是否与此有关。
    • 它知道它已加载,因为它附加到对象上下文。尝试一些在#2 中的 Where 子句之前调用 AsNoTracking() 的示例。然后你会发现 Entry(foreignKey).State 是 Detached,步骤 #4 应该跟踪为 false。
    • 在我的应用程序中附加了相关实体,尽管它们并没有被上下文具体化。我猜它相当于:ctx.Attach(new foreignKey() { Id = 4, SomeProperty = 6 }); 在这种情况下,该对象是一个实际的 foreignKey 对象,而不是一个 foreignKey 代理对象。
    • 请查看我对原始帖子的编辑以获得更详细的说明。
    猜你喜欢
    • 2012-01-27
    • 2021-09-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多