在 C 语言中的多个方法之间使用 Dapper 事务#

Use Dapper transaction between multiple methods in C#

提问人:Farzad Karimi 提问时间:7/16/2023 最后编辑:marc_sFarzad Karimi 更新时间:7/16/2023 访问量:371

问:

我有一个类,其中包含许多方法,这些方法具有不同的插入和更新,以使用 Dapper 进行操作。

我在一种方法中调用了其中一些,并希望为所有这些方法进行一个事务。

像这样的东西:

public bool OrderItemChange(int OrderItem)
{
    using (var con = await Connection.GetOpenConnection())
    {
            using (var trans = con.BeginTransaction())
            {
                 try 
                 {
                    // It's better if I don't send 'con' and 'trans' to all these methods
                    Find(OrderItem);
                    Remove(OrderItem);
                    Save(OrderItem);

                    trans.commit();
                 }
                 catch(exception ex)
                 {
                     trans.Rollback();
                 }       
            }
    }
}

我见过一些这样的答案

但我想知道是否有比向每个方法传递和参数更好、更简单的方法。SqlConnectionSqlTransaction

C# 方法 参数 事务 dapper

评论

4赞 Flydog57 7/16/2023
事务与连接相关联。您不能遵循正常的“在每个数据库操作上创建连接”模式。每个方法都需要传递该信息,或者您需要使它们都成为同一类的成员,并让该类能够感知事务
4赞 Charlieface 7/16/2023
“如果有比传递 SqlConnection 和 SqlTransaction 更好、更简单的方法”不是真的,只是你可以让它成为一个工作单元类,而不仅仅是一个方法。然后,您可以保留 conenction 和事务,并在方法中处理它Dispose
0赞 JHBonarius 7/16/2023
您的示例无法编译。这是一个返回的方法,但你永远不会返回。在提出问题时,请给出一个最小的可重复的例子boolbool

答:

3赞 beautifulcoder 7/16/2023 #1

您需要传入 ,以使每个新连接都知道事务。tras

Find(OrderItem, trans);
Remove(OrderItem, trans);
Save(OrderItem, trans);

然后,当您打开一个新连接时:

using conn = new SqlConnection(ConnectionString);
var count = conn.Execute(sql, transaction: trans);
0赞 Kenan BAŞDEMİR 7/16/2023 #2

您可以通过单独的静态方法执行事务和错误管理。因此,您可以将 Connection 和 BeginTransaction 事务分开。 示例用法如下:

public static class Transaction 
{
    public static async Task Execute(Action<SqlConnection> action) 
    {
        using(var trans = new TransactionScope()) 
        {
            using(var con = await Connection.GetOpenConnection()) 
            {
                try 
                {
                    action(con);
                    trans.Complete();
                } 
                catch (Exception ex) 
                {
                    throw;
                }
            }
        }
    }
}

您可以按如下方式使用该示例。

public async Task OrderItemChange(int OrderItem) 
{
    await Transaction.Execute(con => 
    {
        Find(con, OrderItem);
        Remove(con, OrderItem);
        Save(con, OrderItem);
    });
}

评论

0赞 JHBonarius 7/16/2023
尽管这可行,但它正在重新设计现有的 TransactionScope
1赞 Kenan BAŞDEMİR 7/16/2023
感谢您的回报,我已经通过添加 TransactionScope 的使用进行了编辑。@JHBonarius
1赞 JHBonarius 7/16/2023
好吧,好吧......那不是我要说的。Vivek Nuna 已经展示了如何使用它。无论如何,第二件事是这并没有真正做任何事情。那么你为什么需要它呢?catch (Exception ex) { throw; }
0赞 Kenan BAŞDEMİR 7/16/2023
可能想检查方法错误,这就是我添加它的原因。@JHBonarius
2赞 Vivek Nuna 7/16/2023 #3

您可以使用 .但是您需要传递 to 方法。TransactionScopecon

using System.Data;
using System.Transactions;
using Dapper;

public class YourClass
{
    public bool OrderItemChange(int orderItem)
    {
        using (var scope = new TransactionScope())
        {
            try
            {
                using (var con = Connection.GetOpenConnection())
                {
                    Find(OrderItem, con);
                    Remove(OrderItem, con);
                    Save(OrderItem, con);

                    scope.Complete(); // Commit transaction
                }
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        return true;
    }
}

评论

0赞 beautifulcoder 7/16/2023
将连接重用于多个查询可能会导致并发系统中出现死锁。