【问题标题】:POCO navigation property not updating when foreign key is assigned a value为外键赋值时 POCO 导航属性未更新
【发布时间】: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


【解决方案1】:

最后,我正在完全按照文档中的描述进行操作。我是

为外键属性分配新值。

是的,Entity Framework 确实在修复中对此进行了管理。是的,文档确实说明了这一点。

但事实证明,鸡蛋最终落在了我的脸上。我检查了从 T4 模板生成的类,发现所有导航属性都标记为 virtual。但是,我没有彻底检查以注意到外键属性没有标记为virtual。这似乎是 EF 提供的 T4 模板在模型或数据库优先工作时使用的默认行为。我已经通过在 T4 模板的 CodeStringGenerator.Property() 方法中更改这一行来解决这个问题

Accessibility.ForProperty(edmProperty)

到

AccessibilityAndVirtual(Accessibility.ForProperty(edmProperty))

最后,像往常一样,遵循文档(此处为 POCO 上 EF 更改跟踪的要求)通常会导致依赖代码的行为与文档一致。真丢人。

【讨论】:

    猜你喜欢
    • 2011-01-03
    • 1970-01-01
    • 2021-11-10
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2011-01-01
    相关资源
    最近更新 更多