2012-05-10 80 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(); 
}