【发布时间】:2012-05-08 23:41:06
【问题描述】:
我想在多个表上运行多个插入语句。我正在使用 dapper.net。我没有看到任何处理 dapper.net 交易的方法。
请分享您对如何使用 dapper.net 进行交易的想法。
【问题讨论】:
标签: c# transactions dapper
我想在多个表上运行多个插入语句。我正在使用 dapper.net。我没有看到任何处理 dapper.net 交易的方法。
请分享您对如何使用 dapper.net 进行交易的想法。
【问题讨论】:
标签: c# transactions dapper
这里是代码sn-p:
using System.Transactions;
....
using (var transactionScope = new TransactionScope())
{
DoYourDapperWork();
transactionScope.Complete();
}
请注意,您需要添加对System.Transactions 程序集的引用,因为默认情况下不引用它。
【讨论】:
Dispose() 方法中自动完成。如果Complete()没有被调用,事务被回滚。
TransctionScope 内打开连接。
我更喜欢使用更直观的方法,直接从连接中获取交易:
// 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() 之后才能打开?如果是这种情况,这种扩展方法会促进事务的错误使用。 (IMO,它甚至应该抛出“连接已经打开后无法打开事务”。)
Execute 中,因为这是必需的。
你应该可以使用TransactionScope,因为 Dapper 只运行 ADO.NET 命令。
using (var scope = new TransactionScope())
{
// open connection
// insert
// insert
scope.Complete();
}
【讨论】:
考虑到您所有的表都在单个数据库中,我不同意这里的一些答案中建议的TransactionScope 解决方案。参考this答案。
TransactionScope一般用于分布式事务;跨越不同数据库的事务可能在不同的系统上。这需要在操作系统和 SQL Server 上进行一些配置,否则将无法正常工作。如果您的所有查询都针对单个数据库实例,则不建议这样做。
但是,对于单个数据库,当您需要将代码包含在不受您控制的事务中时,这可能很有用。单库也不需要特殊配置。
connection.BeginTransaction 是针对单个数据库实现事务(在 C#、VB.NET 等中)的 ADO.NET 语法。这不适用于多个数据库。
所以,connection.BeginTransaction() 是更好的选择。
处理事务的更好方法是按照this 答案中的说明实施 UnitOfWork。
【讨论】:
TransactionScope,这对于OP想要的东西效率低下。我同意TransactionScope 在很多情况下是个好工具;但不是这个。
在 Dapper 中进行交易有 3 种方法。
您可以从官方教程网站here了解更多关于这些交易方式的信息
这里是交易方法的细分供参考
1.简单交易
在此示例中,您在现有数据库连接上创建事务,然后将事务传递给 dapper 上的 Execute 方法(这是一个可选参数)。
完成所有工作后,只需提交事务即可。
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。来自交易范围的交易
如果您想创建事务范围,则需要在创建数据库连接之前执行此操作。创建事务范围后,您可以简单地执行所有操作,然后执行一次调用来完成事务,然后提交所有命令
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.使用 Dapper 交易
这是在代码中实现事务的最有利的方法,因为它使代码易于阅读和实现。 SQL Transaction 的扩展实现称为 Dapper Transaction(您可以找到 here),它允许您直接运行 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();
}
}
【讨论】:
IDbTransaction 上添加 Execute 扩展方法本身就是 Dapper 的天才。
IDbConnection 和IDbTransaction。通常你只会传递IDbConnection,但如果你也在一个事务中,你将不得不同时传递IDbTransaction。直到刚才我才意识到IDbTransaction 包含它来自的IDbConnection。所以现在我了解这位 25 年前的 Microsoft 开发人员在设计 ADO.net 接口时的想法 - 只需传递 IDbTransaction。
丹尼尔的回答对我来说是预期的。为了完整起见,这里有一个 sn-p,它使用事务范围和 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 方法,只是它被调用了两次。至于“第二次调用 dispose 没有害处”这一点,这是一个很大的假设。我了解到文档和实际实现通常不一致。但如果你想要微软的话:msdn.microsoft.com/en-us/library/…