我会提供一个答案,以及我使用 EF、Unit of Work 和 Repository Pattern 实现的代码。
答案
从文档中可以看到:
如果要回滚事务,则不应在事务范围内调用Complete方法。例如,您可以在范围内抛出异常。它所参与的事务将被回滚。
请查看他们在链接中分享的示例。这些示例非常有说明性(我将在下面复制其中一个示例,以防万一)。
实现示例
我的实现
这是我必须保存到数据库中的内容,来自 MVC 项目:
我在实现这个方法时遇到了以下问题:
void SaveTheThing(tracker, driver, manager, destination, transportation);
请阅读评论:
using (TransactionScope scope = new TransactionScope())
{
int driverId = SavePerson(driver);
int destinationId = SaveDestination(destination);
transportation.id_person_driver = driverId;
transportation.id_destination = destinationId;
int transportationId = SaveTransportation(transportation);
int managerId = SavePerson(manager);
tracker.id_person_manager = managerId;
tracker.id_transportation = transportationId;
SaveTracker(tracker);
throw new Exception("Roll it back!");
scope.Complete();
_unitOfWork.Save();
}
在
SaveWhatever(whatever)
函数中,使用了
SaveChanges()
以及其他与DbContext和DbSet相关的方法。
并且,在控制器中(这是一个MVC项目):
try
{
SaveTheThing(tracker, driver, manager, destination, transportation);
}
catch (TransactionAbortedException taEx)
{
Console.WriteLine(taEx.Message);
return View("Edit", vm);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return View("Edit", vm);
}
请记住,这种方法存在一些问题,我仍需调查:在EF或我的存储库中存在一些持久性,只要连接是打开的(我正在解决它,我会在修复后更新)。但是,是的,DB没有接收到数据并且回滚实际上已经完成。
阅读材料
示例(来自文档)
static public int CreateTransactionScope(
string connectString1, string connectString2,
string commandText1, string commandText2)
{
int returnValue = 0;
System.IO.StringWriter writer = new System.IO.StringWriter();
try
{
using (TransactionScope scope = new TransactionScope())
{
using (SqlConnection connection1 = new SqlConnection(connectString1))
{
connection1.Open();
SqlCommand command1 = new SqlCommand(commandText1, connection1);
returnValue = command1.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command1: {0}", returnValue);
using (SqlConnection connection2 = new SqlConnection(connectString2))
{
connection2.Open();
returnValue = 0;
SqlCommand command2 = new SqlCommand(commandText2, connection2);
returnValue = command2.ExecuteNonQuery();
writer.WriteLine("Rows to be affected by command2: {0}", returnValue);
}
}
scope.Complete();
}
}
catch (TransactionAbortedException ex)
{
writer.WriteLine("TransactionAbortedException Message: {0}", ex.Message);
}
Console.WriteLine(writer.ToString());
return returnValue;
}