如何将交易与 dapper.net 一起使用

本文关键字:net 一起 dapper 交易 | 更新日期: 2023-09-27 18:32:37

我想在多个表上运行多个插入语句。我正在使用 dapper.net。我看不到任何方法可以处理 dapper.net 交易。

请分享您对如何使用 dapper.net 交易的想法。

如何将交易与 dapper.net 一起使用

这里是代码片段:

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 中进行交易有 3 种方法。

  1. 简单交易
  2. 交易范围中的交易
  3. 使用 Dapper 事务(额外的 nuget 包和最受欢迎的方法(

您可以从官方教程网站找到有关这些交易方法的更多信息

这里

作为参考,以下是交易方法的细分

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事务有一个扩展的实现,称为Dapper Transaction(你可以在这里找到(,它允许你直接运行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();
    }
}
你应该

能够使用TransactionScope因为Dapper只运行 ADO.NET 命令。

using (var scope = new TransactionScope())
{
   // open connection
   // insert
   // insert
   scope.Complete();
}

考虑到您的所有表都在单个数据库中,我不同意此处某些答案中建议TransactionScope解决方案。请参考此答案。

  1. TransactionScope通常用于分布式事务;跨不同数据库的事务可能位于不同的系统上。这需要在操作系统和SQL Server上进行一些配置,否则将无法工作。如果所有查询都针对数据库的单个实例,则不建议这样做。
    但是,对于单一数据库,当您需要在不受您控制的事务中包含代码时,这可能很有用。对于单一数据库,它也不需要特殊配置。

  2. connection.BeginTransaction ADO.NET 语法,用于针对单一数据库实现事务(在 C# 中、VB.NET 等(。这不适用于多个数据库。

所以,connection.BeginTransaction()是更好的方法。

处理事务的更好方法是实现本答案中解释的UnitOfWork。

丹尼尔的回答对我来说是预期的。为了完整起见,下面是一个代码片段,演示了使用事务范围和 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