2012-05-10 38 views
8

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

那么,拒绝更改的最佳方法是什么?而且,我们如何知道上下文是否正在做某件事(IsBusy)?

回答

11

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上下文当修改确实确认后

上下文正在做某件事情,如果你说它做某事。它永远不会变得繁忙。

+0

重新创建上下文将是一个很好的解决方案。但是,我在同步相关数据时遇到了问题。一个例子是,我在ViewA上的CollectionA上有CRUD,在ViewB上有在COllectionB上的CRUD。 CollectionB还拥有对CollectionA的引用。因此,如果我有2个Context对象(既适用于CollectionA也适用于CollectionB),如果我更改ViewA的CollectionA,如何同步ViewB?当有一个上下文时,所有内容都是同步的,因为我们实际上只处理一个实例collectionA,而不是两个。重新创建“全局”上下文会造成混乱。 :)我使用“全局”上下文犯了错误吗? – Goran

+0

至于“忙”,我担心如果我发出一个异步加载负载会发生什么,然后我尝试发出另一个负载,而以前没有完成?这样我可以检查它是否“忙碌”,这样我可以排队一个新的Load。 – Goran

+0

+1注意到大多数人似乎错过了什么。关系:可以通过查看State!= Unchanged的Entries集合来追踪那些不会被拾取的变化。 (EF v6。) – mwardm

1

这个工作对我来说:

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); 
     } 
    } 
} 

这个=的DbContext在这种情况下

+1

删除的实体呢?另外,如何为其他用户更改的实体获取新数据,而不是您? – Goran

2

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

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

虽然问题是关于收集变化,而不是单个实体,但我没有看到没有任何答案对你有帮助?你上面的答案(TheSoul75)与你的建议完全一样,只是它对于收集中的所有物品都是一样的。 – Goran

+0

戈兰,如果集合中的所有更改都被拒绝,那么我的数据将是无效的。只有集合中的其中一个项目需要恢复为原始值。我需要更细化的方法。我知道有时候其他人也需要精细控制。我发布了答案来帮助其他有类似要求的人。 – Tarzan

+1

那么,你不使用foreach,但你基本上使用相同的techicque(刷新与StoreWins),所以我没有看到你的答案增值,因为你刚刚删除了循环。 – Goran

11
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; 
         } 
       } 
      } 
     } 
+0

这似乎是处理所有状态而不触碰数据库的唯一答案。 +1 – Dan

+0

如果我只更改了参考文献,该怎么办?特别纯m:n当没有任何外键属性受到影响? – springy76

0

这可能是一个古老的答案,但有用的任何新的访问者.... 的刷新功能将重新载入数据源对象并覆盖现有的变化新加载的实体的状态将保持不变。

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