Jos*_*eph 6 c# sql-server transactions asp.net-2.0
我有一个Web应用程序,它向DAL中的3个数据库发出请求.我正在编写一些集成测试,以确保整个功能往返实际上完成了我期望它做的事情.这与我的单元测试完全分开,只是fyi.
我打算写这些测试的方式是这样的
[Test]
public void WorkflowExampleTest()
{
(using var transaction = new TransactionScope())
{
Presenter.ProcessWorkflow();
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Presenter已经建立.问题在ProcessWorkflow方法中发挥作用,因为它调用各种存储库,而这些存储库又访问不同的数据库,而我的sql server框没有启用MSDTC,所以每当我尝试创建新的sql连接时,我都会收到错误,或者尝试更改缓存连接的数据库以定位另一个数据库.
为简洁起见,Presenter类似于:
public void ProcessWorkflow()
{
LogRepository.LogSomethingInLogDatabase();
var l_results = ProcessRepository.DoSomeWorkOnProcessDatabase();
ResultsRepository.IssueResultstoResultsDatabase(l_results);
}
Run Code Online (Sandbox Code Playgroud)
我已经尝试了很多东西来解决这个问题.
我在列表上的第三次尝试看起来像这样:
public void LogSomethingInLogDatabase()
{
using (var transaction =
new TransactionScope(TransactionScopeOption.RequiresNew))
{
//do some database work
transaction.Complete();
}
}
Run Code Online (Sandbox Code Playgroud)
实际上我尝试的第三件事实际上是让单元测试工作,但所有完成的事务实际上都是我的数据库!所以这是一个彻头彻尾的失败,因为整个观点是不影响我的数据库.
因此,我的问题是,鉴于我已经制定的限制,还有哪些其他选择可以实现我想要做的事情?
编辑:
这就是"//做一些数据库工作"的样子
using (var l_context = new DataContext(TargetDatabaseEnum.SomeDatabase))
{
//use a SqlCommand here
//use a SqlDataAdapter inside the SqlCommand
//etc.
}
Run Code Online (Sandbox Code Playgroud)
并且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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
好的,我找到了解决这个问题的方法。我这样做的唯一原因是因为我找不到任何其他方法来解决这个问题,并且因为它在我的集成测试中,所以我不担心这会对生产代码产生不利影响。
我必须向 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();
}
}
Run Code Online (Sandbox Code Playgroud)
这允许我的集成测试采用以下形式:
[Test]
public void WorkflowExampleTest()
{
(using var transaction = new TransactionScope())
{
DataContext.SuppressConnectionDispose = true;
Presenter.ProcessWorkflow();
}
}
Run Code Online (Sandbox Code Playgroud)
我不建议在生产代码中使用它,但对于集成测试我认为它是合适的。另请记住,这仅适用于服务器以及用户始终相同的连接。
我希望这可以帮助其他遇到与我相同问题的人。