交易与精巧点网

Ami*_*mit 98 c# transactions dapper

我想在多个表上运行多个insert语句.我正在使用dapper.net.我没有看到任何方法来处理与dapper.net的交易.

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

the*_*ric 95

这里的代码片段:

using System.Transactions;    
....    
using (var transactionScope = new TransactionScope())
{
    DoYourDapperWork();
    transactionScope.Complete();
}
Run Code Online (Sandbox Code Playgroud)

请注意,您需要添加对System.Transactions程序集的引用,因为默认情况下不引用它.

  • 是否有必要显式回滚错误或System.Transactions是否自动处理? (4认同)
  • 值得一提的是因为另一个答案(/sf/answers/1403358281/):如果您选择此答案,必须使用块在`TransctionScope`内打开连接. (4认同)
  • @NorbertNorbertson它在`Dispose()`方法中自动完成.如果尚未调用`Complete()`,则事务将被回滚. (3认同)
  • 另请参阅(/sf/answers/1403358281/)-DoYouDapperWork(执行,查询等)需要参数中的事务。 (2认同)
  • 如果您的 DoYourDapperWork() 使用多个 SqlConnections 来完成这项工作,这是否有效?例如,假设我有一个简洁的存储库,其中每个方法都使用一个新连接。我可以将其中的几个包装称为 TransactionScope 吗? (2认同)

ANe*_*ves 88

我更喜欢通过直接从连接获取事务来使用更直观的方法:

// 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();
}
Run Code Online (Sandbox Code Playgroud)

  • 必须在.begintransaction之前调用connection.open() (22认同)
  • 将事务作为参数包含在 `Execute` 中的好点,因为这是必需的。 (4认同)

New*_*per 68

在 Dapper 中有 3 种进行交易的方法。

  1. 简单交易
  2. 交易范围内的交易
  3. 使用 Dapper Transaction(额外的 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
}
Run Code Online (Sandbox Code Playgroud)

3. 使用 Dapper 事务

在我看来,这是在代码中实现事务的最有利的方法,因为它使代码易于阅读且易于实现。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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是正确的答案。我很惊讶我必须到最后一个答案才能找到它。其他答案是*不要使用 Dapper*,或*不要使用 Tranaasctions*。这解释了事务如何“应该”与 Dapper 一起工作 - 以及 Dapper “意图”我们如何使用事务。额外奖励:现在我明白了,在“IDbTransaction”本身上添加 **Execute** 扩展方法对于 Dapper 来说是天才。 (4认同)
  • @IanBoyd 我很高兴这个答案能够有所帮助,我想我只是来晚了一点,但我想我会分享一些我最近使用 Dapper 的理解和学习 (3认同)
  • 每当我需要一个子方法来执行数据库工作时,我总是传递“IDbConnection”和“IDbTransaction”。通常,您只需传递“IDbConnection”,但如果您也在事务中,则将被迫同时传递“IDbTransaction”。直到现在我才意识到`IDbTransaction`包含它来自的`IDbConnection`。所以现在我**明白** 25 年前 Microsoft 开发人员在设计 ADO.net 接口时的想法 - 仅传递“IDbTransaction”。 (2认同)

Dan*_*ite 18

您应该可以使用,TransactionScope因为Dapper只运行ADO.NET命令.

using (var scope = new TransactionScope())
{
   // insert
   // insert
   scope.Complete();
}
Run Code Online (Sandbox Code Playgroud)


Ami*_*shi 6

考虑到您的所有表都在单个数据库中,我不同意TransactionScope这里的一些答案中建议的解决方案.请参阅答案.

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

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

所以,connection.BeginTransaction()是更好的方式去.

处理事务的更好方法是实现UnitOfWork,如答案中所述.

  • 一个不需要多个数据库来从TransactionScope中受益.特别有用的是它的环境.在事务中包装您不拥有或无法修改的代码非常有用.例如,当单元/集成测试代码执行数据库调用之后要回滚的位置时,可以使用它.只需浮动TransactionScope,测试代码,并在测试清理期间进行处理. (4认同)
  • @LarrySmith:同意; 但问题不在于此.OP只是说他想在一个事务中插入多个表.一些答案,包括被接受的答案,建议使用`TransactionScope`,这对于OP想要的效率低.我同意`TransactionScope`在很多情况下都是很好的工具; 但不是这个. (3认同)

Sud*_*hra 5

丹尼尔的回答对我来说按预期工作。为了完整起见,这里有一个片段,它演示了使用事务范围和 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 
Run Code Online (Sandbox Code Playgroud)

  • 那么,代码分析警告是您拒绝投票的理由吗?这不会使答案错误或具有误导性 - 那是适当的反对票。为什么不编辑答案并提出更好的解决方案,同时保持功能?堆栈溢出是关于帮助和建设性的批评。 (3认同)
  • @usr 归结为个人喜好。我更愿意在第一次出现问题时知道,不要将日志语句视为垃圾。此外,我的答案仍然通过展示一种使用 dapper 进行交易的方式来展示价值 (2认同)