C# 如何使用dapper.net的事务?
我想在多个表上运行多个insert语句。我正在使用dapper.net。我看不出用dapper.net处理事务的任何方法C# 如何使用dapper.net的事务?,c#,transactions,dapper,C#,Transactions,Dapper,我想在多个表上运行多个insert语句。我正在使用dapper.net。我看不出用dapper.net处理事务的任何方法 请分享您关于如何使用dapper.net的事务的想法。您应该能够使用TransactionScope,因为dapper只运行ADO.net命令 using (var scope = new TransactionScope()) { // open connection // insert // insert scope.Complete(); }
请分享您关于如何使用dapper.net的事务的想法。您应该能够使用
TransactionScope
,因为dapper只运行ADO.net命令
using (var scope = new TransactionScope())
{
// open connection
// insert
// insert
scope.Complete();
}
下面是代码片段:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
请注意,您需要添加对
System.Transactions
程序集的引用,因为默认情况下它不被引用 我更喜欢使用更直观的方法,直接从连接获取事务:
// 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();
}
丹尼尔的回答对我来说正如预期的那样有效。为了完整起见,下面是一个演示使用事务作用域和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
使用系统事务;
//\u sqlConnection已在前面代码中的其他位置打开
使用(var transactionScope=new transactionScope())
{
尝试
{
long result=_sqlConnection.ExecuteScalar(sqlString,new{Param1=1,Param2=“string”});
transactionScope.Complete();
}
捕获(异常)
{
//记录器在代码中的其他地方初始化
_logger.Error(异常,$“执行SQL时遇到错误:{sqlString},消息:{exception.Message}”)
//重新抛出,让来电者知道
投掷;
}
}//这是调用Dispose的地方
考虑到您所有的表都在一个数据库中,我不同意这里的一些答案中建议的TransactionScope
解决方案。参考答案
TransactionScope
通常用于分布式事务;跨不同数据库的事务可能位于不同的系统上。这需要在操作系统和SQL Server上进行一些配置,如果没有这些配置,这将无法工作。如果您的所有查询都针对单个数据库实例,则不建议这样做。但是,对于单个数据库,当您需要在不受您控制的事务中包含代码时,这可能很有用。对于单个数据库,它也不需要特殊配置
connection.BeginTransaction
是ADO.NET语法,用于对单个数据库实现事务(在C#、VB.NET等中)。这不适用于多个数据库connection.BeginTransaction()
是更好的方法
甚至更好的处理事务的方法是实现UnitOfWork,如回答中所述。有3种方法可以简洁地处理事务
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
connection.Execute(sql, new {CustomerName = "Mark"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "Sam"}, transaction: transaction);
connection.Execute(sql, new {CustomerName = "John"}, transaction: transaction);
transaction.Commit();
}
}
2。来自交易范围的交易
如果要创建事务作用域,则需要在创建db连接之前执行此操作。一旦创建了事务作用域,就可以简单地执行所有操作,然后执行一个调用来完成事务,然后提交所有命令
using (var transaction = new TransactionScope())
{
var sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = My.ConnectionFactory())
{
connection.Open();
connection.Execute(sql, new {CustomerName = "Mark"});
connection.Execute(sql, new {CustomerName = "Sam"});
connection.Execute(sql, new {CustomerName = "John"});
}
transaction.Complete();
}
3。使用简洁的事务处理
这是在代码中实现事务的最有利方法,因为它使代码易于阅读和实现。有一个SQL事务的扩展实现,称为Dapper事务(您可以找到),它允许您直接在事务之外运行SQL执行
string sql = "INSERT INTO Customers (CustomerName) Values (@CustomerName);";
using (var connection = new SqlConnection(FiddleHelper.GetConnectionStringSqlServerW3Schools()))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
transaction.Execute(sql, new {CustomerName = "Mark"});
transaction.Execute(sql, new {CustomerName = "Sam"});
transaction.Execute(sql, new {CustomerName = "John"});
transaction.Commit();
}
}
@ANeves:嗯,我们可能使用不同的Dapper框架,因为这个框架有:必须在.beginTransaction之前调用connection.open()。除非在transactionscope中打开连接,否则连接不会自动登记到transactionscope中。我不知道你的代码是如何工作的,如果GetOpenConnection在transactionscope中以某种方式神奇地打开自己,但我敢打赌它不会t@ErikBergstedt,您是说只有在我们调用
.BeginTransaction()
后,连接才能打开吗?如果是这样的话,这种扩展方法将促进事务的错误使用。(依我看,它甚至应该抛出“连接已打开后无法打开事务”。)最好将事务作为参数包含在Execute
中,因为这是必需的。@usr这取决于个人偏好。我更喜欢知道第一次出错的时候,不要把日志语句看作垃圾。此外,我的回答还通过演示一种使用事务的方法来宣传价值dapper@CodeNaked首先,你的订单错了。如果出现异常,将首先命中catch块,然后到达使用范围的末尾。第二,看看这个答案和引用的MSDN文档:第二次调用dispose是无害的,设计良好的对象会忽略第二次调用。否决票是没有道理的@dotnetguy-我并没有试图传达第一次或第二次调用哪个Dispose
方法,只是调用了两次。至于“第二次调用dispose没有害处”这一点,这是一个很大的假设。我了解到文档和实际实现往往不一致。但如果你想要微软的话:那么,代码分析警告是你否决投票的理由吗?这并不意味着答案是错误的或是误导性的——这是投反对票的时候了。为什么不编辑答案并提出更好的解决方案,同时保留功能?堆栈溢出是关于帮助和建设性的批评。它是必要的吗