2009-04-17 52 views
6

我有一個Web應用程序向DAL中的3個數據庫發出請求。我正在編寫一些集成測試,以確保整體功能的往返實際上完成我所期望的功能。這與我的單元測試完全分開,只是fyi。如果MSDTC被禁用,如何繞過TransactionScope中的多個數據庫連接?

我正打算寫這些測試的方式是事在這種情況下,主持人已經建立了這個

[Test] 
public void WorkflowExampleTest() 
{ 
    (using var transaction = new TransactionScope()) 
    { 
     Presenter.ProcessWorkflow(); 
    } 
} 

效果。這個問題在ProcessWorkflow方法中發揮作用,因爲它調用各種存儲庫,而這些存儲庫又訪問不同的數據庫,並且我的sql服務器框沒有啓用MSDTC,所以無論何時嘗試創建新的sql連接或嘗試將緩存連接的數據庫更改爲另一個目標。

爲了簡潔演示類似像:

public void ProcessWorkflow() 
{ 
    LogRepository.LogSomethingInLogDatabase(); 
    var l_results = ProcessRepository.DoSomeWorkOnProcessDatabase(); 
    ResultsRepository.IssueResultstoResultsDatabase(l_results); 
} 

我已經嘗試了許多事情來解決這個問題。

  1. 緩存在任何時候都一個活動連接,並改變目標數據庫
  2. 緩存爲每個目標數據庫一個活動連接(這是一種無用的,因爲池應該這樣做對我來說,但我想看看我得到了不同的結果)
  3. 添加額外的TransactionScopes每一個倉庫內,讓他們使用TransactionScopeOption「RequiresNew」

我的名單上的第三嘗試看起來像這樣有自己的交易:

public void LogSomethingInLogDatabase() 
{ 
    using (var transaction = 
     new TransactionScope(TransactionScopeOption.RequiresNew)) 
    { 
     //do some database work 

     transaction.Complete(); 
    } 
} 

實際上,我嘗試的第三件事實際上得到了單元測試的工作,但所有事務實際上完成HIT我的數據庫!所以這是一個徹底的失敗,因爲整個問題不會影響我的數據庫。

因此,我的問題是,有什麼其他選項可以完成我想要做的事情嗎?

編輯:

這就是 「//做一些數據庫工作」 看起來像

using (var l_context = new DataContext(TargetDatabaseEnum.SomeDatabase)) 
{ 
    //use a SqlCommand here 
    //use a SqlDataAdapter inside the SqlCommand 
    //etc. 
} 

和DataContext的本身看起來像這樣

public class DataContext : IDisposable 
{ 
    static int References { get; set; } 
    static SqlConnection Connection { get; set; } 

    TargetDatabaseEnum OriginalDatabase { get; set; } 

    public DataContext(TargetDatabaseEnum database) 
    { 
     if (Connection == null) 
      Connection = new SqlConnection(); 

     if (Connection.Database != DatabaseInfo.GetDatabaseName(database)) 
     { 
      OriginalDatabase = 
       DatabaseInfo.GetDatabaseEnum(Connection.Database); 

      Connection.ChangeDatabase(
       DatabaseInfo.GetDatabaseName(database)); 
     }   

     if (Connection.State == ConnectionState.Closed) 
     { 
      Connection.Open() //<- ERROR HAPPENS HERE 
     }  

     ConnectionReferences++;     
    } 

    public void Dispose() 
    { 
     if (Connection.State == ConnectionState.Open) 
     { 
      Connection.ChangeDatabase(
       DatabaseInfo.GetDatabaseName(OriginalDatabase)); 
     } 

     if (Connection != null && --ConnectionReferences <= 0) 
     { 
      if (Connection.State == ConnectionState.Open) 
       Connection.Close(); 
      Connection.Dispose(); 
     } 
    } 
} 
+0

我不確定我關注。你什麼意思是工作單位? – Joseph 2009-04-17 16:18:31

+0

對不起,我們在這裏談論多個數據庫服務器或與單個服務器的多個連接? – meandmycode 2009-04-17 16:26:19

回答

1

好吧,我找到了解決這個問題的方法。我這樣做的唯一原因是因爲我找不到任何其他解決此問題的方法,並且因爲它在我的集成測試中,所以我並不擔心這會對生產代碼產生不利影響。

我只好一個屬性添加到我的DataContext作爲一個標誌來跟蹤我的DataContext正出售時是否處置連接的對象。這樣,連接在整個交易範圍保持活力,因此不再困擾DTC

這是我的新處置的樣本:

internal static bool SupressConnectionDispose { get; set; } 

public void Dispose() 
{ 
    if (Connection.State == ConnectionState.Open) 
    { 
     Connection.ChangeDatabase(
      DatabaseInfo.GetDatabaseName(OriginalDatabase)); 
    } 

    if (Connection != null 
     && --ConnectionReferences <= 0 
     && !SuppressConnectionDispose) 
    { 
     if (Connection.State == ConnectionState.Open) 
      Connection.Close(); 
     Connection.Dispose(); 
    } 
} 

這使我的集成​​測試採取的形式:

[Test] 
public void WorkflowExampleTest() 
{ 
    (using var transaction = new TransactionScope()) 
    { 
     DataContext.SuppressConnectionDispose = true; 

     Presenter.ProcessWorkflow(); 
    } 
} 

我不會推薦在生產代碼中使用它,但對於集成測試我認爲它是合適的。另請注意,這僅適用於服務器始終與用戶相同的連接。

我希望這可以幫助別人誰運行到同樣的問題,我有。

0

如果您不想使用MSDTC,你可以直接使用SQL事務。

請參閱SqlConnection.BeginTransaction()

相關問題