【发布时间】:2020-01-17 21:49:21
【问题描述】:
我有一个用作实体框架实体的 POCO 类 (OPERATION)。此类具有导航属性 (OP) 和指向同一相关实体 (OP_ID) 的外键。
在一个方法中,我得到一个OPERATION,在这个OPERATION 上,OP_ID 和OP 都是null。当我将OP_ID 设置为此外键的有效值时,OP 导航属性仍然是null。当我明确检测到上下文的变化时,OP 导航属性现在被分配了正确的值。
示例代码
public bool UpdateOperation(operationID)
{
IQueryable<OPERATION> operations = from o in base.ctx.OPERATION
select o;
OPERATION operation = operations
.Where(o => o.OPERATION_ID == operationID)
.Include("OP")
.FirstOrDefault();
if (operation != null)
{
operation.OP_ID = opId;
}
// operation.OP is null here
operation.GetContext().ChangeTracker.DetectChanges();
// operation.OP is populated here
}
我已经确认operation 实际上是一个动态代理。值得一提的是,一旦我检测到更改,operation.OP 也会成为动态代理。然而,即便如此,为operation.OP_ID 分配一个不同 值仍然需要显式调用DetectChanges() 以更新operation.OP 的值。
更新
针对@ErikPhilips 的评论,here 文档似乎暗示这应该发生。具体来说:
以下示例展示了如何使用外键属性和导航属性来关联相关对象。通过外键关联,您可以使用任一方法来更改、创建或修改关系。对于独立关联,您不能使用外键属性。
通过为外键属性分配新值,如下例所示。
course.DepartmentID = newCourse.DepartmentID;...
当您使用上述方法之一更改附加到上下文的对象的关系时,Entity Framework 需要保持外键、引用和集合同步。 Entity Framework 使用代理自动管理 POCO 实体的这种同步(也称为关系修复)。
如果您使用没有代理的 POCO 实体,则必须确保调用 DetectChanges 方法以同步上下文中的相关对象。
一些额外的上下文也可能有用。这是一个遗留应用程序,过去直接使用ObjectContext 而不是DbContext,尽管那时使用的是EF 6。我们现在正在迁移到DbContext API。此特定代码未经任何修改,用于演示我所期望的行为。具体来说,当分配OP_ID 时,我可以在调试器中看到OP 属性被自动填充以指向正确的OPERATION。
【问题讨论】:
-
为什么它会自动这样做?任何地方都没有文件说明发生或应该发生的情况。最好不要发生这种情况,因为如果对许多对象执行值更改,则加载对象可能会损害性能(因为每个对象都是对数据库的一次调用)。
-
好问题,@ErikPhilips。我在我的问题中添加了一些额外的细节,希望能为您解答。
-
我们可以从他们自己的文档中看到,更改外键需要调用
.Load()。 Loading related object -
虽然文档在修复(对象同步)方面很差,但根据我的经验,修复仅在对象已加载到内存中(代理与否)时才会发生,或者您正在访问主要的导航属性代理对象上的键未更改。
-
最后一点,如果我调用
DetectChanges()(以便将对象加载到内存中)然后再次更改外键,我必须调用@987654350 @again 用于第二次更新导航属性。关于文档,与您的第一条评论相反,文档非常清楚地指出“通过为外键属性分配新值......实体框架自动管理此同步。” :) 让我完全困惑的是当我直接使用ObjectContext时这是如何工作的。
标签: c# entity-framework