2010-09-15 29 views
7

據NHProf,使用隱式事務的氣餒:如何在使用存儲庫模式的事務中保留IQueryable <>?

http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions

然而,從數據庫中讀取對象時NHibernate的LINQ返回IQueryable<>,這是懶洋洋地評估。我有一個倉庫這個方法:

public IQueryable<T> GetAll<T>() 
{ 
    using (var transaction = _session.BeginTransaction()) 
    { 
     var data = _session.Linq<T>(); 
     transaction.Commit(); 
     return data; 
    } 
} 

的問題在這裏是評估data之前該方法將提交事務。有沒有辦法使用存儲庫模式,並保持IQueryable<>明確的交易?或者讀取操作是否可以使用隱式事務?

+4

爲什麼要在讀操作周圍進行事務? – 2010-09-15 19:44:45

+3

啊,從文章中看到:「即使我們只讀數據,我們也應該使用一個事務,因爲使用事務可以確保我們從數據庫中獲得一致的結果.NHibernate假定對數據庫的所有訪問都是在一個事務中完成的,強烈不鼓勵在沒有交易的情況下使用會話。「但是,我完全不明白爲什麼作者正在做出這種聲明。 – 2010-09-15 19:52:37

回答

5

存儲庫應該而不是創建一個事務。這是一個單獨的層的責任(這取決於應用程序類型)。

+0

我同意,我想你的解釋爲什麼你認爲它是一個單獨的層的責任是這樣的:事務邊界應該由用戶或其他應用程序交互的方式來定義。每個請求的Web應用程序示例,每個服務調用的服務,Windows應用程序的每個「點擊一個按鈕」,每個移動的遊戲等等。當事務由存儲庫創建時,創建存儲庫會更困難獨立於應用程序與其交互的方式,並且也可能使其難以在一般情況下使用。 – Paco 2010-09-15 22:52:47

3

我想重構這個以允許外部事務控制。除非進行調用的代碼告訴它,否則存儲庫無法知道各種讀/寫調用所屬工作單元的範圍。考慮設置「工作單元」模式:不透露數據存儲實現的具體細節,允許依賴於存儲庫的對象指定它們開始,中止或完成「工作單元」。

public interface IRepository 
{ 
    public UnitOfWork BeginUnitOfWork() 

    public void CommitUOW(UnitOfWork unit) 

    public void AbortUOW(UnitOfWork unit) 

    public IQueryable<T> GetAll<T>(UnitOfWork unit) 

    public List<T> GetAll<T>() 

    public void Store<T>(T theObject, UnitOfWork unit) 

    public void Store<T>(T theObject) 
} 

你的版本庫可能會通過維護SQL事務,每個鍵到的UnitOfWork對象的私人字典實現這個(這可能是一個空的實例化類一樣簡單,也可以提供有關國家框架無關信息或指標)。在執行數據庫操作時,您的呼叫者首先要求開始一個UoW,並且他們將獲得一個令牌,用於標識他們進行數據庫調用的上下文。獲取令牌的對象可以將它傳遞給需要在同一操作上下文中執行數據庫操作的其他類。工作單元將保持打開狀態,直到依賴類告訴存儲庫已完成,允許延遲加載和原子多操作過程。

請注意,有重載不需要工作單元。在沒有明確啓動一個工作單元的情況下進行簡單調用是可能的,也許是必要的。在這些情況下,您的Repository可以創建一個內部UOW,執行請求的操作並返回結果。然而,在這些情況下,延遲加載將是困難的或不可能的;您必須在結束內部UoW之前將整個結果集檢索到列表。

1

我與迭戈在這一個 - 存儲庫無法知道交易範圍。

我還擔心返回IQueryable - 據我瞭解,它有很多額外的查詢方法,可能很難進行單元測試。我更喜歡返回IEnumerable並在存儲庫方法中封裝更復雜的查詢。否則,您將不得不根據GetAll()的輸出對各種查詢進行單元測試。

+1

單元測試IQueryable的所有方法真的是你的工作嗎?你不應該只是你寫的單元測試代碼嗎? – Gabe 2010-09-15 21:02:55

+0

@Gabe:我擔心的不是單元測試IQueryable,而是單元測試在無數位置使用的查詢的_results_。我已經讀過其他人說它是查詢邏輯的生存位置,但我更喜歡像GetFulfilledOrders()這樣的複雜的linq查詢方法來返回相同的結果。更容易測試和更清晰。 – n8wrl 2010-09-16 11:49:47

相關問題