30

MVC 3 + EF 4.1在MVC中實例化和處理DbContext的最佳方式是什麼?

我對付的DbContext兩種方法之間進行選擇:

  1. 實例化Application_BeginRequest,放入 HttpContext.Current.ItemsApplication_EndRequest處理。
  2. (爲DbContext kindof包裝)創建一次性的UnitOfWork並 開始using(var unitOfWork = new UnitOfWork()) { ... }

每個控制器動作分享您的體驗,請:一個你會喜歡哪一種?每種方法有哪些優缺點?

+0

使用塊方法有一些缺點。它會導致很多往返數據庫和濫用Entity框架中的事務。請參閱http://ayende.com/blog/4775/new-profiler-feature-avoid-writes-from-multiple-sessions-in-the-same-request – marvelTracker

+0

爲什麼會導致更多往返?一個http請求應該在大多數情況下運行一個動作,所以如果你將整個動作的代碼包裝到這個使用塊中,與第一種方法相比,不會有更多的數據庫請求。 「每操作」方法的另一件事是,您應該始終注意數據庫可能被調用的作用域並適當地放置該塊。例如,如果您的模型包含一些要在一段時間視圖渲染中加載的集合,則返回View(Model)的語句應該位於該塊內部。 – YMC

+0

如果在控制器層中使用DbContext,則UnitOfWork會在UI層和數據庫方法中創建強依賴關係。然後你需要一個服務層和存儲庫層。之後,如果您的存儲庫使用單獨的UnitOfWork,並使用將成爲問題的塊。因爲每個存儲庫都會創建事務和不必要的數據庫往返。請參閱上面的鏈接瞭解更多詳情如果你確定每個請求有一個服務調用,那麼你可以在服務方法內部使用單元工作。但是,這不是保證。 – marvelTracker

回答

18

我會建議你使用依賴注入框架。您可以將DbContext爲每個請求

container.RegisterType<MyDbContext>().InstancePerHttpRequest(); 

註冊並注入它作爲一個構造函數參數傳遞給控制器​​。

public class MyController : Controller 
{ 
    public MyController(MyDbContext myDbContext) 
    { 
     _myDbContext = myDbContext; 
    } 
} 

如果註冊類型實現IDisposable則請求結束時的DI框架將它丟棄。

第一種方法:使用ID框架要比手動實現它清潔得多。進一步你的請求可能不需要你的UoW。

第二種方法:控制器不應該知道如何構建你的UoW(DbContext)。目的不是減少組件之間的耦合。

+0

對,使用IoC容器比處理BeginRequset和EndRequest更好,但它對我來說仍然非常接近數字1,這就是爲什麼我甚至沒有將它作爲單獨的方法提取出來的原因。對我來說更重要的是比較2種訪問和控制DbContext(=工作單元)生命週期的方式:第一種方式意味着ASP.NET/IoC基礎設施負責它,第二種方式是關於每個控制器操作收費。 – YMC

+0

@YMC編輯答案。你的第二種方法將在你的控制器和UoW實現之間引入耦合。我建議你避免它。 – Eranga

+3

介紹服務層並向控制器注入服務。服務可以有許多存儲庫,並且存儲庫依賴於使用EFDbContext的UnitOfWork包裝。然後使用DI來注入這些依賴關係。然後,您可以獲得關注分離的優勢。 – marvelTracker

-1
+2

OP沒有說把DbContext放在一個靜態字段中......他想把它放在HttpContext.Current.Items中,就我所見,這是非常安全的 –

+0

我沒有說我把DbContext放到了global.asax中。我說我放置了實例化和配置DbContext的代碼。 DbContext在HttpContext.Current.Items中。它是線程安全的。 – YMC

2

我們目前使用通過服務定位器從存儲庫工廠實例化的UoW(工作單元)注入的存儲庫。 Unity通過這種方式控制了你的工作。

您的具體實施將取決於如果您使用POCO的,實體對象等變化..

最終你想UOW如果你要在你的控制器不止一個對象集一起工作,以確保您只使用一個上下文。這將保持您的交易檢查等。

如果你打算使用多個objectcontexts(即多個EDMX的),你會想看看使用UoW與MSDTC ...但這可能比你想知道的更多。最終,重要的是確保你實例化控制器操作所需的內容(即上下文的一個實例)。我不認爲我會使用Begin_Request,你可能甚至不需要每個請求的上下文。

相關問題