如果禁用MSDTC,如何绕过TransactionScope内的多个数据库连接?
我有一个Web应用程序,它向DAL中的3个数据库发出请求。 我正在编写一些集成测试,以确保整个function往返实际上完成了我期望它做的事情。 这与我的unit testing完全分开,只是fyi。
我打算写这些测试的方式是这样的
[Test] public void WorkflowExampleTest() { (using var transaction = new TransactionScope()) { Presenter.ProcessWorkflow(); } }
在这种情况下,Presenter已经建立。 问题在ProcessWorkflow方法中发挥作用,因为它调用各种存储库,而这些存储库又访问不同的数据库,而我的sql server框没有启用MSDTC,所以每当我尝试创建新的sql连接时,我都会收到错误,或者尝试更改缓存连接的数据库以定位另一个数据库。
为简洁起见,Presenter类似于:
public void ProcessWorkflow() { LogRepository.LogSomethingInLogDatabase(); var l_results = ProcessRepository.DoSomeWorkOnProcessDatabase(); ResultsRepository.IssueResultstoResultsDatabase(l_results); }
我已经尝试了很多东西来解决这个问题。
- 始终缓存一个活动连接并更改目标数据库
- 为每个目标数据库缓存一个活动连接(这有点无用,因为池应该为我做这个,但我想看看我是否得到了不同的结果)
- 在每个存储库中添加其他TransactionScope,以便使用TransactionScopeOption“RequiresNew”拥有自己的事务
我在列表上的第三次尝试看起来像这样:
public void LogSomethingInLogDatabase() { using (var transaction = new TransactionScope(TransactionScopeOption.RequiresNew)) { //do some database work transaction.Complete(); } }
实际上我尝试的第三件事实际上是让unit testing工作,但所有完成的事务实际上都是我的数据库! 所以这完全是失败,因为整个观点是不影响我的数据库。
因此,我的问题是,鉴于我所制定的限制,还有哪些其他方案可以实现我想要做的事情?
编辑:
这就是“//做一些数据库工作”的样子
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(); } } }
好的,我找到了解决这个问题的方法。 我这样做的唯一原因是因为我找不到任何其他方法来解决这个问题,并且因为它在我的集成测试中,所以我并不担心这会对生产代码产生负面影响。
我必须在我的DataContext中添加一个属性作为一个标志,以便在处理我的DataContext时跟踪是否处置连接对象。 这样,连接在整个事务范围内保持活动,因此不再困扰DTC
这是我新Dispose的样本:
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(); } }
这允许我的集成测试采取以下forms:
[Test] public void WorkflowExampleTest() { (using var transaction = new TransactionScope()) { DataContext.SuppressConnectionDispose = true; Presenter.ProcessWorkflow(); } }
我不建议在生产代码中使用它,但对于集成测试,我认为这是合适的。 另请注意,这仅适用于服务器始终相同的连接以及用户。
我希望这可以帮助遇到同样问题的其他人。
-
在连接字符串上设置Enlist = false以避免在事务上自动登记。
-
手动登记连接作为事务范围的参与者。 (https://msdn.microsoft.com/en-us/library/ms172153%28v=VS.80%29.aspx)
如果您不想使用MSDTC,则可以直接使用SQL事务。
请参见SqlConnection.BeginTransaction()
。
上述就是C#学习教程:如果禁用MSDTC,如何绕过TransactionScope内的多个数据库连接?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注---计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/960827.html