C# 我对IsLoaded的理解正确吗?

C# 我对IsLoaded的理解正确吗?,c#,.net,entity-framework,ef-code-first,change-tracking,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 ent

下面是一些代码以及我基于在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
    这样的延迟加载来检索它(查询数据库)
  • 获取
    记录
    实体的详细信息
  • 这是我不确定的部分。在我的测试中,它输出
    true
    。我猜IsLoaded不知道
    record.ForeignKey
    当前是否有值,但知道
    record.ForeignKey
    已在上下文中根据其对
    record.ForeignKeyId
    的了解和已建立的关系进行跟踪
  • 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);
    
  • 检索一些记录(查询数据库)是,结果记录附加到DbContext。
  • 检索恰好是记录的外键属性的记录,而不使用诸如record.ForeignKey之类的延迟加载来检索它(查询数据库)是的。如果您想在#1中急切地加载外键,那么应该使用context.MyTable.Include(m=>m.ForeignKey.First();这将在1次查询中检索记录和fk。
  • 获取记录实体的详细信息<有点。。。它是与DbContext相关的实体的详细信息(附加/删除/加载的内容等)
  • 这是我不确定的部分。在我的测试中,结果是真的。我猜IsLoaded不知道record.ForeignKey当前是否有值,但知道record.ForeignKey已在上下文中根据其对record.ForeignKeyId和已建立的关系的了解进行跟踪这意味着DbContext不需要运行另一个查询来加载外键的数据。如果执行record.ForeignKey,则数据已经存在,不需要额外的数据库访问
  • db在这里似乎没有被命中,我假设这是出于同样的原因,IsLoaded在4中返回true。它知道它已经在跟踪foreignKey对象,因此它知道它不必进行延迟加载实体已在步骤2中加载,因此无需额外行程即可从db获取。
  • 问题编辑后更新

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

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

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

    在这两个代码段中,您都加载了
    记录
    ,其中有一个外键指向
    ForeignKeyTable
    。上下文知道这个值。(顺便说一句,您是否在模型中公开了外键并不重要。它将始终被加载,模型中也没有FK属性。您可以在查看SQL查询时看到这一点。)

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

    显然,
    IsLoaded
    不会告诉您实体是否附加到上下文,因为在这两个示例中,实体都附加了,但一个返回
    true
    ,另一个返回
    false
    。它也不会告诉您,
    record.ForeignKeyId
    是否引用实体,因为在两个示例中都是这样

    它显然只告诉您实体实际上是从数据库加载的(而不仅仅是手动附加的)(Intellisense也说是关于
    IsLoaded
    )。这是第一个和第二个示例之间的唯一区别

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


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

    我知道,如果使用Include,它将与外键一起加载记录。我更想知道它是如何知道它已经在步骤4中加载的。我在应用程序中运行了类似的测试,步骤4返回false。相当于
    foreignKey
    的加载方式不会创建对象代理,因此我想知道它是否与此有关。它知道加载它是因为它附加到对象上下文。尝试一些在#2中Where子句之前调用AsNoTracking()的示例。你
    // 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);