【问题标题】:DbContext and RejectChangesDbContext 和拒绝更改
【发布时间】:2012-05-19 02:33:51
【问题描述】:

我正在使用 RIA 服务,其中 ObjectContext 具有 RejectChanges() 方法。但是,我现在正在桌面应用程序中使用 EF 4.4,但找不到该方法。所以,我的问题是:在我允许用户对集合进行批量 CrUD 操作的场景中,我将如何恢复所有更改?我可以重新创建上下文并再次获取数据,但如果我需要将更改恢复为 1-2 个实体,这听起来非常不必要。

那么,拒绝更改的最佳方式是什么?还有,我们如何知道上下文是否在做某事(IsBusy)?

【问题讨论】:

    标签: entity-framework


    【解决方案1】:

    EF 没有任何直接的“拒绝更改”操作。您可以浏览ChangeTracker / ObjectStateManager 中的实体条目,并用修改后的实体的原始值覆盖当前值。您还可以分离添加的实体并将已删除的实体更改回未更改的实体,但只有在您(或内部 EF)没有更改任何独立关联(关系)的状态时,所有这些都将主要工作。如果你也使用关系,整个事情会变得更加复杂,因为你也必须恢复关系——在这种情况下,重新加载数据会更简单。

    要恢复 DbContext API 中的更改,您可以尝试以下操作:

    foreach (var entry in context.ChangeTracker
                                 .Entries<YourEntityType>()
                                 .Where(e => e.State == EntityState.Modified))
    {
        entry.CurrentValues.SetValues(entry.OriginalValues);
    }
    

    在这种情况下,我认为主要问题是您使用实体的方式 - 您允许对实时数据进行更改,EF 在后面执行其逻辑以在执行更改时保持数据一致,但稍后您决定这些更改将不能得救。在这种情况下,您应该执行以下操作之一:

    • 丢弃更改的数据并重新加载整个数据集(通过重新创建上下文)
    • 分离此逻辑,不处理实时数据,仅在真正确认修改后将数据修改推送到 EF 上下文

    如果你说它做某事,上下文就是在做某事。它本身永远不会变得忙碌。

    【讨论】:

    • 重新创建上下文将是一个很好的解决方案。但是,我在同步相关数据时遇到了问题。一个例子是我在 ViewA 上的 CollectionA 上有 CRUD,在 ViewB 上的 COllectionB 上有 CRUD。 CollectionB 还持有对 CollectionA 的引用。因此,如果我有 2 个 Context 对象,同时用于 CollectionA 和 CollectionB,如果我在 ViewA 上更改 CollectionA,我将如何同步 ViewB?当拥有一个 Context 时,一切都是同步的,因为我们实际上只处理一个实例 collectionA,而不是两个。重新创建“全局”上下文会造成混乱。 :) 我使用“全局”上下文是否犯了错误?
    • 至于“忙碌”,我担心如果我以异步方式发出负载,然后我尝试发出另一个负载,而之前没有完成,会发生什么?这样我可以检查它是否“忙”,所以我可以排队一个新的负载。
    • +1 表示注意到大多数人似乎想念的内容。关系:通过查看 State != Unchanged 的​​ Entries 集合,可以跟踪不会被拾取的更改。 (EF v6.)
    【解决方案2】:
    public void RejectChanges()
            {
                foreach (var entry in ChangeTracker.Entries())
                {
                    switch (entry.State)
                    {
                        case EntityState.Modified:
                            {
                                entry.CurrentValues.SetValues(entry.OriginalValues);
                                entry.State = EntityState.Unchanged;
                                break;
                            }
                        case EntityState.Deleted:
                            {
                                entry.State = EntityState.Unchanged;
                                break;
                            }
                        case EntityState.Added:
                            {
                                entry.State = EntityState.Detached;
                                break;
                            }
                    }
                }
            }
    

    【讨论】:

    • 这似乎是处理所有状态而不访问数据库的唯一答案。 +1
    • 如果我只更改引用会怎样?当没有任何外键属性受到影响时,尤其是纯 m:n?
    【解决方案3】:

    我知道这是一个老问题。但是,没有一个答案适合我的情况。我需要拒绝对集合中仅 1 个实体的更改。这对我有用:

        var objectContext = (myDbContext as IObjectContextAdapter).ObjectContext;
        objectContext.Refresh(RefreshMode.StoreWins, partMaster);
    

    【讨论】:

    • 虽然问题是关于集合更改,而不是单个实体,但我看不出答案对您有何帮助?您上面的答案(TheSoul75)与您的建议完全相同,只是它对集合中的所有项目都是如此。
    • Goran,如果集合中的所有更改都被拒绝,那么我的数据将无效。集合中只有一项需要恢复为原始值。我需要一个更细化的方法。我知道有时其他人也需要精细控制。我发布答案是为了帮助其他有类似要求的人。
    • 好吧,您不使用 foreach,但您本质上使用的是相同的技术(使用 StoreWins 刷新),所以我没有看到您的答案中的附加值,因为您刚刚删除了循环。
    【解决方案4】:

    这对我有用:

    public void RejectChanges() {
        var context = ((IObjectContextAdapter)this).ObjectContext;
        foreach (var change in this.ChangeTracker.Entries()) {
            if (change.State == EntityState.Modified) {
                 context.Refresh(RefreshMode.StoreWins, change.Entity);
            }
            if (change.State == EntityState.Added) {
                 context.Detach(change.Entity);
            }
         }
    }
    

    this=DbContext 在这种情况下

    【讨论】:

    • 被删除的实体呢?此外,您将如何获取由其他用户(而不是您)更改的实体的新数据?
    【解决方案5】:

    这可能是一个旧答案,但对任何新访问者都有用.... Reload 函数将从数据源重新加载对象并覆盖任何现有的更改,并且新加载的实体将具有未更改的状态。

    public static void UndoEntityChanges(object Entity)
    {
        <EFModelContainer>.Entry(Entity).Reload();
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-11
      • 2015-12-24
      • 1970-01-01
      • 1970-01-01
      • 2020-08-04
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多