【问题标题】:Why does Setting EntityState to Detached Empty a Property of type List<T>?为什么将 EntityState 设置为 Detached 会清空 List<T> 类型的属性?
【发布时间】:2012-04-26 22:42:49
【问题描述】:

首先使用实体​​框架代码,我有类似的东西:

public class Foo
{
    public int Id { get; set; }

    public List<Bar> Bars { get; set; }
}    

Foo foo = (from f in ctx.Foos.Include("Bars") where f.Id == 42 select f).Single();

// At this point foo.Bars is populated

ctx.Entry(foo).State = EntityState.Detached;

// At this point foo.Bars is an empty List

为什么分离一个对象会导致它的属性public List&lt;string&gt; Bars被清空?

分离可能具有许多属性的对象的正确过程是什么?

【问题讨论】:

    标签: entity-framework-4 ef-code-first


    【解决方案1】:

    列表被清空的原因是Entity Framework中两个规则的组合:

    1. 当你分离一个对象时,只有这个对象本身被分离,没有任何导航属性引用的对象。

    2. ObjectContext/DbContext 不允许保存部分附加到上下文并部分分离的对象图。虽然这可能会在使用 POCO 时作为临时状态发生,但 EF 将始终通过在各种方法(如AddAttach、设置实体的状态等)内部的图形中自动附加分离的对象来修复此临时状态或调用SaveChanges 时最晚。

    这意味着当您从上下文中分离根对象时,EF 将清除子对象列表,因为:a) 子对象保持连接(规则 1)和 b) 图表中分离对象和附加对象的混合不会允许(规则 2)。

    据我所知,在保持原始树结构的同时,无法将对象图从上下文中分离出来。您可以将父级分离,然后将子级一个接一个地分离。结果,您已将树的所有对象从上下文中分离出来,但树同时被销毁 - 每个导航属性都无效。

    手动分离实体的主要目的是在您有内存资源限制并且不希望并且需要在上下文中保存大量对象的情况下释放它们以进行垃圾回收。为此,图结构被破坏并不重要。

    我不知道为什么需要从上下文中分离对象。但请记住,还可以选择从数据库中加载实体而不首先将它们附加到上下文中,例如使用 AsNoTracking()

    关于 MSDN 文档的一些参考问题的另一个答案在这里:https://stackoverflow.com/a/7693732/270591

    【讨论】:

    • DbContext 早在我的对象被释放之前就超出了范围。使用AsNoTracking() 加载我的对象会允许收集 DbContext,还是我的对象仍会保持对它的引用?这是我最关心的问题。
    • @EricJ.:您首先使用的是 EF 代码,因此您的实体是 POCO。如果你不使用延迟加载(看起来你没有因为Foo.Bars 不是virtual)那么实体不是代理并且它们没有对上下文的引用。所以,答案是肯定的,即使您仍然持有对实体的引用,上下文也会被垃圾收集。
    • 如果实体是代理,那么在释放实体之前不会对上下文进行垃圾回收?
    • @EricJ.:我想是的,是的。因为代理在内部具有对上下文的引用来执行延迟加载。但我不确定,也许可以就此提出一个新问题。
    • 很好的解释。但是,如果您想将缓存(比如 Redis)与 EF Core 集成怎么办?它会给跟踪带来很多问题,尤其是导航属性。对此有何见解?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    相关资源
    最近更新 更多