2011-06-14 28 views
2

場景:如何將ef4上下文或至少某些實體恢復到其原始值?

  1. 檢索一些實體
  2. 更新這些實體
  3. 你進行某種形式的,這就決定你應該不再有這些屬性更新的業務邏輯的一些性質;相反,您應該插入一些記錄業務邏輯結果的新實體。
  4. 插入新實體
  5. SaveChanges();

顯然在上面的例子中調用SaveChanges()不僅會插入新的實體,而且會更新原始實體的屬性。在我設法重新安排我的代碼之前,只有當我知道我希望保存所有更改時纔會更改上下文(及其實體),但這並非總是可行。所以問題是處理這種情況的最好方法是什麼?我不直接使用上下文,而是通過存儲庫,如果這很重要。有沒有簡單的方法來恢復實體的原始值?這種情況下的最佳做法是什麼?

更新

雖然我與拉吉斯拉夫不同意的業務邏輯應該以這樣的方式,驗證始終任何修改的實體之前來重新安排,我同意該解決方案確實應該堅持就想改變不同的背景。我不同意的原因是因爲我的業務交易相當長,並且在交易結束時可能發生的驗證或錯誤檢查並不總是顯而易見的。想象一下你用從上到下的燈光裝飾的聖誕樹,當你在下面的分支上工作時,你已經修改了樹。如果其中一盞燈壞了會發生什麼?您想要回滾所有更改,但您希望創建一些ERROR實體。正如Ladislav所建議的,最直接的方法是將ERROR實體保存在不同的上下文中,從而允許原始的(帶有修改的隱喻樹)到期而不會調用SaveChanges。

現在,在我的情況下,我利用Ninject進行依賴注入,將一個EF上下文注入到我所有位於頂級服務範圍內的存儲庫中。這意味着我的業務層類沒有真正控制創建新的EF上下文。他們不僅無法訪問EF上下文(請記住他們通過存儲庫工作),但注入在對象層次結構中已經發生得更高。我找到的唯一解決方案是創建另一個類,它將利用Ninject在其中創建一個新的UOW。

//business logic executing against repositories with already injected and shared (unit of work) context 
Tree = treeRepository.Get(); 
Lights = lightsRepsitory.Get(); 

//update the tree as you're decorating it with lights 

if(errors.Count == 0) 
{ 
    //no errors, calling SaveChanges() on any one repository will commit the entire UOW as they all share the same injected EF context 
    repository1.SaveChanges(); 
} 
else 
{ 
    //oops one of the lights broke, we need to insert some Error entities 
    //however if we just add id to the errorRepository and call SaveChanges() the modifications that happened 
    //to the tree will also be committed. 
    TreeDecoratorErroHandler.Handle(errors);  
} 

internal class TreeDecoratorErroHandler 
{ 
    //declare repositories 
    //constructor that takes repository instances 

    public static void Handle(IList<Error> errors) 
    { 
     //create a new Ninject kernel 
     using(Ninject... = new Ninject...) 
     { 
      //this will create an instance that will get injected with repositories sharing a new EF instance 
      //completely separate from the one outside of this class 
      TreeDecoratorErroHandler errorHandler = ninjectKernel.Get<TreeDecoratorErroHandler>(); 
      //this will insert the errors and call SaveChanges(), the only changes in this new context are the errors 
      errorHandler.InsertErrors(errors); 
     }  
    } 

    //other methods 
} 

回答

1

您應該爲此使用新的上下文。上下文是工作單元,一旦你的業務邏輯說:「嘿,我不想更新這個實體」,那麼實體不是工作單元的一部分。您可以分離實體或創建新的上下文。

有可能使用Refresh方法,但該方法應該用於需要處理樂觀併發的場景。因爲這種方法只刷新標量和複雜屬性和外鍵(如果實體的一部分) - 如果您對導航屬性進行了更改,那麼在刷新實體後這些屬性仍然存在。

+0

問題是我的服務類注入了正確的存儲庫,而這個存儲庫又被注入了一個EF上下文。該上下文可能與諸如HTTP請求之類的東西綁定在一起,跨所有這些應用程序在多個存儲庫和服務中共享。我真的不知道如何在服務本身中發佈某種命令來繼續並在所有實例化的存儲庫中重新注入上下文。 – e36M3 2011-06-15 12:19:20

+0

也許分離是一個更好的選擇。如果我還通過導航屬性更改了其他實體,我需要弄清楚如何正確分離實體。例如Student.Classes.Add(Math);分離學生可能是不夠的。 – e36M3 2011-06-15 12:25:49

+0

看起來您的業務邏輯已經癱瘓了。只有在確實需要保存更改時,才能以修改實體的方式編寫邏輯。每個請求實例都是推薦的簡化解決方案,但是您的邏輯需要每個請求更多的上下文實例。 – 2011-06-15 12:33:36

0

看看ObjectContext.Refresh與RefreshMode.StoreWins我認爲這將做你想做的。開始一個新的上下文會達到我猜想的同樣的事情,但不會那麼整齊。

+0

拉迪斯拉夫講述了納維特性。最好啓動一個新的工作單元/環境 – Andiih 2011-06-14 22:56:18