用于 Connection.Query 的 Trans.commit

Trans.commit for Connection.Query

提问人:Lia Lucindia 提问时间:11/11/2023 最后编辑:Lia Lucindia 更新时间:11/12/2023 访问量:49

问:

我在下面有一个函数,它将通过存储过程将值插入到SQL DB中。我正在尝试实现trans.commit以使其更好,但是使用sp_insertTransaction2的存储过程在第一次插入时一直遇到错误:

当分配给命令的连接位于挂起的本地事务中时,ExecuteReader 要求命令具有事务。命令的 Transaction 属性尚未初始化

我在网上看到了很多教程,但是使用SQLCommand来初始化trans而不是使用连接。像我的代码一样查询。需要帮助来解决问题。

public bool insertTransactions(string receiver, string deliverer, string module, DateTime date, bool isChkout, int timeLapse, List<Lot> Lots)
{

    using (var connection = new SqlConnection(ConnString))
    {
        connection.Open();
        var trans = connection.BeginTransaction();
        try
        {
            var data = connection.Query<TransactionsModel>("[sp_insertTransaction2]",
            new
            {
                receiver,
                deliverer,
                module,
                date,
                isChkout,
                timeLapse
            },
            commandTimeout: 120, commandType: CommandType.StoredProcedure);

            **trans.Commit();**

            foreach (var lot in Lots)
            {
                var data2 = connection.Query<TransactionsModel>("[sp_insertLot]",
                 new
                {
                    lot.LotVPO,
                    lot.Bin,
                    lot.Location,
                    lot.Qty,
                },
                 commandTimeout: 120, commandType: CommandType.StoredProcedure);
            trans.Commit();
       }
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine("insertTransactions API error : " + ex.ToString());
            trans.Rollback();
            return false;
        }
    }
C# SQL Dapper

评论

2赞 Alexander Petrov 11/11/2023
你的存储过程,从名称来看,做插入,对吧?因此,请使用该方法而不是 .ExecuteQuery
0赞 Charlieface 11/12/2023
对于基本的批量插入,请考虑使用 .SqlBulkCopy

答:

1赞 Nick Vidalis 11/11/2023 #1

您正确地开始了交易,但您需要在每个 .有一个 IDbTransaction 方法参数。connection.BeginTransaction();transQuery<>()

此外,您不能提交两次事务。如果确实需要,您需要开始一个新的查询,但通常您在一个事务中完成所有查询并在最后提交。

评论

0赞 Lia Lucindia 11/11/2023
您是否有关于如何将事务 var trans 输入到 Query<>() 的示例?我在网上搜索了 IDbTransaction,但没有使用 Query<>() 代码大小写。
0赞 Nick Vidalis 11/11/2023
@LiaLucindia 首先,我假设您正在查看代码来使用 Dapper。例如,尝试在方法参数的末尾添加。您的 IDE(如果您使用的是 IDE)应该会为您提供帮助。, transaction: trans
0赞 Lia Lucindia 11/11/2023
这行得通。我只需要在commandTimeout:120之前指定trans,它就可以工作了。} trans, commandTimeout: 120...感谢您的帮助!
0赞 Alander 11/12/2023
我不同意这个答案,如果代码有效并不意味着它是交易的正确用法
0赞 Alander 11/12/2023 #2

这是因为你有多个 ,其中一个在 for 循环中。commit

事务意味着一切都成功完成,或者某些事情失败并触发了回滚。

如果你的目的是保存交易记录及其批号,那么你只能提交一次,否则将导致错误

dapper 提供了一个更好的类,如果代码未执行,该类将自动回滚TransactionScopescope.Complete()

此外,用于读取行、插入/更新/删除 use 和 use 语句,用于连接和 transactionscope,因此它将自动关闭QueryExecuteusing

public bool insertTransactions(string receiver, string deliverer, string module, DateTime date, bool isChkout, int timeLapse, List<Lot> Lots)
{
    try
        {
            using (var connection = new SqlConnection(ConnString))
            {
                connection.Open();
                using (var scope = new TransactionScope()) // use scope instead, its better
                {   //use Execute when you insert/update/delete, Query is only for read
                    var data = connection.Execute<TransactionsModel>("[sp_insertTransaction2]",
                    new {
                    receiver,
                    deliverer,
                    module,
                    date,
                    isChkout,
                    timeLapse
                    }, commandTimeout: 120, commandType: CommandType.StoredProcedure);

                    foreach (var lot in Lots)
                    {
                        //use Execute when you insert/update/delete, Query is only for read
                        var data2 = connection.Execute<TransactionsModel>("[sp_insertLot]",
                        new
                        {
                        lot.LotVPO,
                        lot.Bin,
                        lot.Location,
                        lot.Qty,
                        }, commandTimeout: 120, commandType: CommandType.StoredProcedure);
                
                    }
                    scope.Complete(); //Or it will automatically rollback, call it only once! 
                }
                
            }   
        }
        catch (Exception ex)
        {
            Console.WriteLine("insertTransactions API error : " + ex.ToString());
            trans.Rollback();
            return false;
        }
}