2009-04-17 51 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()

相关问题