3

如果這看起來像是重複的問題,請事先道歉。 This question是我能找到的最接近的,但它並不能真正解決我所面臨的問題。實體框架5工作單元模式 - 我應該在哪裏調用SaveChanges?

我在ASP.NET MVC4應用程序中使用實體框架5,並試圖實現工作單元模式。

我的工作類的單元實現IDisposable,包含我DbContext派生對象上下文類的一個實例,以及一些資源庫,其中的每一個從一個普通的基庫類派生暴露所有常見的存儲庫功能。

對於每個HTTP請求,Ninject創建Unit of Work類的單個實例並將其注入到控制器中,並在請求完成時自動處理它。

由於EF5將數據存儲抽象出來,Ninject管理對象上下文的生命週期,它似乎是消費代碼訪問內存中實體對象而不需要明確管理其持久性的完美方式。換句話說,爲了優化問題分離,我設想我的控制器操作方法能夠使用和修改存儲庫數據,而不需要以後明確地調用SaveChanges

我的第一個嘗試實現這個想法的嘗試是在修改數據的每個存儲庫基類方法中調用SaveChanges。當然,我很快意識到這不是性能優化(特別是在對同一個方法進行多次連續調用時),也不適用於操作方法直接修改從存儲庫中檢索的對象的屬性的情況。

所以,我發展我的設計,以消除這些SaveChanges過早的電話和工作實例的單元被設置在與一個單一的調用替換它們。這似乎是MVC中工作單元模式的最簡單實現,因爲一個工作單元自然適用於一個請求。

不幸的是,建築這個概念之後,我發現它的致命缺陷 - 的對象添加到或從DbContext刪除是not reflected, even locally的事實,直到SaveChanges被調用。

那麼,你有什麼想法,即消費代碼應該能夠使用對象而不必明確地堅持它們?而且,如果這個想法看起來有效,那麼用EF5實現它的最好方法是什麼?

非常感謝您的建議,

更新:根據@瓦希德的迴應,我加入了下面的一些測試代碼,顯示的一些情況中,它成爲消費代碼至關重要顯式調用SaveChanges

var unitOfWork = _kernel.Get<IUnitOfWork>(); 
var terms = unitOfWork.Terms.Entities; 

// Purge the table so as to start with a known state 
foreach (var term in terms) 
{ 
    terms.Remove(term); 
} 

unitOfWork.SaveChanges(); 

Assert.AreEqual(0, terms.Count()); 

// Verify that additions are not even reflected locally until committed. 
var created = new Term { Pattern = "Test" }; 
terms.Add(created); 
Assert.AreEqual(0, terms.Count()); 

// Verify that additions are reflected locally once committed. 
unitOfWork.SaveChanges(); 
Assert.AreEqual(1, terms.Count()); 

// Verify that property modifications to entities are reflected locally immediately 
created.Pattern = "Test2"; 
var another = terms.Single(term => term.Id == created.Id); 
Assert.AreEqual("Test2", another.Pattern); 
Assert.True(ReferenceEquals(created, another)); 

// Verify that queries against property changes fail until committed 
Assert.IsNull(terms.FirstOrDefault(term => term.Pattern == "Test2")); 

// Verify that queries against property changes work once committed 
unitOfWork.SaveChanges(); 
Assert.NotNull(terms.FirstOrDefault(term => term.Pattern == "Test2")); 

// Verify that deletions are not even reflected locally until committed. 
terms.Remove(created); 
Assert.AreEqual(1, terms.Count()); 

// Verify that additions are reflected locally once committed. 
unitOfWork.SaveChanges(); 
Assert.AreEqual(0, terms.Count()); 
+0

我覺得我和你有同樣的問題。來自NHibernate,我習慣於讓INSERT和DELETE語句直接進入數據庫,這樣當我稍後嘗試選擇對象時(在相同的DbContext會話中),我實際上得到了我的結果。我希望SaveChanges()只是提交事務,但看起來EF延遲了所有的INSERT/DELETE語句,直到調用SaveChanges()。你有沒有想過一個辦法來做它你想做的事(並且我認爲,我們想)? – efdee

回答

7

首先SaveChanges應該不能是曾經在repositori es在所有。因爲這會導致你失去UnitOfWork的好處。

第二個你需要做一個特殊的方法來保存UnitOfWork的變化。

如果您想自動調用此方法,則可以使用其他解決方案,如ActionFilter或者讓所有控制器繼承BaseController類並處理其中的SaveChanges

無論如何,UnitOfWork應始終有SaveChanges方法。

+0

非常感謝您的回覆。我的最新實現可以完成所有你提出的事情,並且它已經包含一個機制,在HTTP請求結束時調用SaveChanges(基於Ninject的InRequestScope綁定)。但是,如果消費代碼修改某些內容而不顯式調用SaveChanges,則這並不能解決即使在單個工作單元的範圍內,對象上下文也可能進入無效狀態的問題。我將用一些代碼更新我的問題以顯示此內容。 –

+0

在使用「服務層」的情況下,其中每個服務具有對「UOW」的引用。我應該在哪裏調用'SaveChanges',以便我可以在其他服務中重用特定的服務方法? –

+0

對我來說,我傳遞一個可選參數來確認在服務層方法'AddEmployee(Employee model,bool save = true)保存更改'如果我沒有傳遞這個參數,那麼服務將保存更改。 –

相關問題