2010-01-21 45 views
6

我有一個方法,我想在抽象意義上是「事務性」。它調用了兩個發生在數據庫中的方法,但這種方法並不知道。方法知道太多的方法調用

public void DoOperation() 
{ 
    using (var tx = new TransactionScope()) 
    { 
     Method1(); 
     Method2(); 

     tc.Complete(); 
    } 
} 

public void Method1() 
{ 
    using (var connection = new DbConnectionScope()) 
    { 
     // Write some data here 
    } 
} 

public void Method2() 
{ 
    using (var connection = new DbConnectionScope()) 
    { 
     // Update some data here 
    } 
} 

由於實質TransactionScope意味着一個數據庫事務將被使用,我們在那裏可以很好地提升爲分佈式事務,如果我們從池中獲取兩個不同的連接問題。對於這樣一個目的

public void DoOperation() 
{ 
    using (var tx = new TransactionScope()) 
    using (var connection = new DbConnectionScope()) 
    { 
     Method1(); 
     Method2(); 

     tc.Complete(); 
    } 
} 

我做DbConnectionScope自己,所以我不必須通過連接對象子方法:

我可以在ConnectionScope包裹DoOperation()方法解決這個問題(這是比我真正的問題更人造的例子)。我從這篇文章的想法:http://msdn.microsoft.com/en-us/magazine/cc300805.aspx

不過,我不喜歡這個解決辦法,因爲它意味着DoOperation現在擁有的知識,它的調用方法可以使用連接(也可能是不同的每個連接)。我如何重構這個來解決這個問題?

一個想法,我想的是創造一個更一般的OperationScope,這樣當有一個自定義的溫莎城堡的生活方式聯手我會寫,會用意味着要求OperationScopeLifetyle容器的任何組件總是會得到相同的該組件的實例。這確實解決了這個問題,因爲OperationScopeDbConnectionScope含糊不清。

+0

什麼?有人投票贊成這個問題被關閉?爲什麼? – 2010-01-23 01:30:14

回答

1

我在這裏看到衝突的要求。

一方面,您不希望DoOperation意識到數據庫連接正在用於其子操作。

另一方面,很清楚意識到這個事實,因爲它使用TransactionScope

我有點理解你時,你說你希望它是在抽象的意義上事務在說什麼,但我採取的是,它幾乎是不可能(沒有,從頭開始 - 完全不可能)用這種抽象的術語來描述交易。遠的不說,你有一個這樣的類:

class ConvolutedBusinessLogic 
{ 
    public void Splork(MyWidget widget) 
    { 
     if (widget.Validate()) 
     { 
      widgetRepository.Save(widget); 
      widget.LastSaved = DateTime.Now; 
      OnSaved(new WidgetSavedEventArgs(widget)); 
     } 
     else 
     { 
      Log.Error("Could not save MyWidget due to a validation error."); 
      SendEmailAlert(new WidgetValidationAlert(widget)); 
     } 
    } 
} 

這個類是這樣做恐怕無法回滾至少兩件事情(設置類的屬性和執行的事件處理程序,它可以例如級聯更新窗體上的某些控件),並且至少還有兩件事肯定無法回滾(附加到某處的日誌文件併發出電子郵件警報)。

也許這似乎是一個人爲的例子,但這實際上是我的觀點;您不能將TransactionScope視爲「黑匣子」。事實上,這個範圍就像任何其他的依賴關係一樣; TransactionScope只是爲一個工作單元提供了一個方便的抽象,可能並不總是合適的,因爲它實際上並未包裝數據庫連接,也無法預測未來。特別是,當單個邏輯操作需要跨越多個數據庫連接時,通常不適用,無論這些連接是針對同一個數據庫還是不同的連接。當然,它試圖處理這種情況,但正如你已經知道的那樣,結果是次優的。

我看到它的方式,你有幾個不同的選擇:

  1. 作出明確的事實,Method1Method2需要通過使它們採取的連接參數的連接,或通過重構它們放到一個類這需要連接依賴(構造函數或屬性)。這樣,連接成爲合同的一部分,因此Method1不再知道太多 - 它確切知道根據設計應該知道的內容。

  2. 接受你DoOperation方法確實有什麼Method1Method2做的意識。其實這個沒有錯!的確,您不想依賴某些未來呼叫的實現細節,但轉發依賴關係在抽象中通常被認爲是可以的;它是反向您需要關注的依賴關係,例如某個深層領域模型的類嘗試更新首先沒有業務知識的UI控件時。

  3. 使用更穩健的Unit of Work模式(另:here)。這種情況越來越流行,總的來說,微軟已經將Linq轉向SQL和EF(DataContext/ObjectContext基本上是UOW實現)。這與DI框架相得益彰,從本質上解決了您需要擔心事務何時開始和結束以及數據訪問如何發生的問題(術語「持久性無知」)。這可能需要對設計進行大量的重新設計,但重磅對於它來說,這將是最容易長期維護的。

希望這些可以幫助你。

+0

我認爲「前進依賴」是什麼使它成爲或打破它。 UoW絕對是我通常會這樣做的,但我正在使用數據表(甚至不是數據集)的遺留應用程序中工作,因此很棘手。感謝你的回答,根據你答案的第二部分,我覺得它更舒服一些。 – 2010-01-23 12:07:26

0

是否可以將事務處理/註冊到數據庫並將其從代碼中完全刪除?

+0

不是。在這種情況下,會發出兩個完全分離的DB命令,但在這種情況下,如果其中一個或另一個失敗,或者其他事件引發異常,我都希望這兩個或兩個都不提交。 – 2010-01-21 23:16:04