Entity framework 4 首先使用EF代码将带有基类的对象层次结构加载到会话中

Entity framework 4 首先使用EF代码将带有基类的对象层次结构加载到会话中,entity-framework-4,ef-code-first,Entity Framework 4,Ef Code First,正如我在问题中发现的那样,使用EF.Include()方法加载派生类的属性是不可能的(这已经被证明) 我通过迭代包含兄弟类型混合的集合来解决这个问题,分别调用 ctx.Entry(myDerivedType).Reference("PropOfDerivedType").Load(); 这会导致许多额外的数据库往返,但至少它是有效的 现在我需要加载这样的对象层次结构,并将其保存在MVC web应用程序的会话中。由于DbContext不应该是会话的一部分,因此我认为必须加载对象图AsNoTrac

正如我在问题中发现的那样,使用EF
.Include()
方法加载派生类的属性是不可能的(这已经被证明)

我通过迭代包含兄弟类型混合的集合来解决这个问题,分别调用

ctx.Entry(myDerivedType).Reference("PropOfDerivedType").Load();
这会导致许多额外的数据库往返,但至少它是有效的

现在我需要加载这样的对象层次结构,并将其保存在MVC web应用程序的会话中。由于
DbContext
不应该是会话的一部分,因此我认为必须加载对象图
AsNoTracking()
,如下所示:

var myGraph = (from my in ctx.MyHierarchyRoot.Include("NonDerivedStuff")
               .AsNoTracking()
               where CONDITION select my).Single();
foreach (SomeBase b in myGraph.SomeCollection)
{
    if (b is SomeConcreteDerivedType)
    {
        ctx.Entry(b).Reference("SomePropertyOfSomeConcreteDerivedType").Load();
    }
}
问题1

如果要在会话中存储对象图,是否有必要且正确地使用
.AsNoTracking()

然后,我继续迭代层次结构中的派生同级,并尝试按如下方式加载它们:

var myGraph = (from my in ctx.MyHierarchyRoot.Include("NonDerivedStuff")
               .AsNoTracking()
               where CONDITION select my).Single();
foreach (SomeBase b in myGraph.SomeCollection)
{
    if (b is SomeConcreteDerivedType)
    {
        ctx.Entry(b).Reference("SomePropertyOfSomeConcreteDerivedType").Load();
    }
}
但是,由于我使用
.AsNoTracking()
加载了myGraph,我得到:

无法为属性调用成员“Load” “SomePropertyOfSomeConcreteDerivedType”因为类型的实体 “SomeConcreteDerivedType”在上下文中不存在。添加 实体到上下文调用的Add或Attach方法 数据库集

问题2

假设问题1的答案为“是”,如何正确加载派生类型的导航属性

如果要在会话中存储对象图,是否有必要且正确地使用
.AsNoTracking()

有必要确保会话中存储的实体不包含对上下文的任何引用(并且不需要上下文)。这应该通过在将实体保存到会话之前分离实体来执行,但分离总是会破坏关系。在这种情况下,最简单的解决方法是禁用代理创建(延迟加载和动态更改跟踪将不起作用)


另一种方法是以正常方式加载实体图,并创建图的深度克隆(序列化)。深度克隆始终与上下文完全分离,并且可以安全地存储在会话中。

对于“持久性无知”解决方案来说,这似乎相当笨拙。您知道EF团队是否计划在这方面进行改进吗?如果禁用代理创建,如何加载派生实体?我需要延迟加载来加载包含许多派生类型的集合,每个派生类型都有不同的属性,而这些属性又必须加载。我仍然可以序列化对象图,但我更愿意使用最轻的重锤来完成这项工作。顺便说一句,我非常感谢您为帮助解决EF问题所做的所有工作。事实证明,如果不禁用代理,我根本无法深度克隆实体图,因为代理类型不是已知类型。例如,我认为您正在使用显式加载(您手动调用
Load
)。我不知道是否有任何改进计划,但我也希望看到他们。分离对象图形很笨拙。序列化动态代理需要在序列化过程中进行一些修改-.NET应该使用
DataContractSerializer
ProxyDataContractResolver
类直接支持这一点。我错误地认为必须创建代理才能在事后加载。在禁用代理创建的情况下加载似乎可以正常工作(尽管仍有许多DB往返)。