Answers:
这里的代码片段:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
请注意,您需要添加对System.Transactions
程序集的引用,因为默认情况下未引用该程序集。
Dispose()
方法中自动执行。如果Complete()
尚未调用,则事务将回滚。
TransctionScope
using块内部打开连接,以防您选择此答案。
我更喜欢使用更直观的方法,直接从连接获取事务:
// This called method will get a connection, and open it if it's not yet open.
using (var connection = GetOpenConnection())
using (var transaction = connection.BeginTransaction())
{
connection.Execute(
"INSERT INTO data(Foo, Bar) values (@Foo, @Bar);", listOf5000Items, transaction);
transaction.Commit();
}
.BeginTransaction()
Execute
,因为这是必需的。
考虑到所有表都在单个数据库中,我不同意TransactionScope
此处一些答案中建议的解决方案。请参阅此答案。
TransactionScope
通常用于分布式交易;跨不同数据库的事务可能在不同系统上。这需要在操作系统和SQL Server上进行一些配置,如果没有这些配置将无法使用。如果所有查询都针对单个数据库实例,则不建议这样做。
但是,对于单个数据库,当您需要将代码包含在不受您控制的事务中时,这可能会很有用。对于单个数据库,它也不需要特殊的配置。
connection.BeginTransaction
是ADO.NET语法,用于针对单个数据库实现事务(在C#,VB.NET等中)。这不适用于多个数据库。
所以, connection.BeginTransaction()
是更好的方法。
处理事务的更好方法是实现此答案中解释的UnitOfWork 。
TransactionScope
对于OP所需的效率低下的答案。我同意TransactionScope
在许多情况下这是个好工具;但不是这个。
丹尼尔的答案符合我的预期。为了完整起见,下面的代码片段演示了如何使用事务作用域和dapper进行提交和回滚:
using System.Transactions;
// _sqlConnection has been opened elsewhere in preceeding code
using (var transactionScope = new TransactionScope())
{
try
{
long result = _sqlConnection.ExecuteScalar<long>(sqlString, new {Param1 = 1, Param2 = "string"});
transactionScope.Complete();
}
catch (Exception exception)
{
// Logger initialized elsewhere in code
_logger.Error(exception, $"Error encountered whilst executing SQL: {sqlString}, Message: {exception.Message}")
// re-throw to let the caller know
throw;
}
} // This is where Dispose is called
Dispose
方法被称为第一个或第二个方法,只是它被调用了两次。关于“第二次呼叫处置无害”这一点,这是一个很大的假设。我了解到,文档和实际的实现常常会不一致。但是,如果您想要微软的话: msdn.microsoft.com/en-us/library/...