ExecuteNonQuery 要求命令具有事务。

8
我在执行下面的代码时,遇到了这个错误信息。
ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction

请问问题出在哪里?我猜问题的根源在于我尝试执行一个存储过程的部分。

这个存储过程在执行时会创建自己的事务。

 using (SqlConnection conn = new SqlConnection(connStr))
            {
                conn.Open();

                SqlCommand command = conn.CreateCommand();
                SqlTransaction transaction;

                // Start a local transaction.
                transaction = conn.BeginTransaction("createOrder");

                // Must assign both transaction object and connection
                // to Command object for a pending local transaction
                command.Connection = conn;
                command.Transaction = transaction;

                try
                {
                    command.CommandText = "INSERT INTO rand_resupply_order (study_id, centre_id, date_created, created_by) " +
                        "VALUES (@study_id, @centre_id, @date_created, @created_by) SET @order_id = SCOPE_IDENTITY()";

                    command.Parameters.Add("@study_id", SqlDbType.Int).Value = study_id;
                    command.Parameters.Add("@centre_id", SqlDbType.Int).Value = centre_id;
                    command.Parameters.Add("@date_created", SqlDbType.DateTime).Value = DateTime.Now;
                    command.Parameters.Add("@created_by", SqlDbType.VarChar).Value = username;

                    SqlParameter order_id = new SqlParameter("@order_id", SqlDbType.Int);
                    //study_name.Value = 
                    order_id.Direction = ParameterDirection.Output;
                    command.Parameters.Add(order_id);

                    command.ExecuteNonQuery();
                    command.Parameters.Clear();

                    //loop resupply list 
                    for (int i = 0; i < resupplyList.Count(); i++)
                    {
                        try
                        {
                            SqlCommand cmd = new SqlCommand("CreateOrder", conn);
                            cmd.CommandType = CommandType.StoredProcedure;

                            cmd.Parameters.Add("@study_id", SqlDbType.Int).Value = study_id;
                            cmd.Parameters.Add("@centre_id", SqlDbType.Int).Value = centre_id;
                            cmd.Parameters.Add("@created_by", SqlDbType.VarChar).Value = username;
                            cmd.Parameters.Add("@quantity", SqlDbType.VarChar).Value = resupplyList[i].Quantity;
                            cmd.Parameters.Add("@centre_id", SqlDbType.Int).Value = centre_id;
                            cmd.Parameters.Add("@depot_id", SqlDbType.VarChar).Value = depot_id;
                            cmd.Parameters.Add("@treatment_code", SqlDbType.Int).Value = centre_id;
                            cmd.Parameters.Add("@order_id", SqlDbType.Int).Value = (int)order_id.Value;
                            cmd.ExecuteNonQuery();
                        }
                        catch (SqlException ex)
                        {
                            transaction.Rollback();
                            ExceptionUtility.LogException(ex, "error");
                            throw ex;
                        }
                        catch (Exception ex)
                        {
                            transaction.Rollback();
                            ExceptionUtility.LogException(ex, "error");
                            throw ex;
                        }
                        finally
                        {
                            conn.Close();
                            conn.Dispose();
                        }

                    }

                    return (int)order_id.Value;

                }
                catch (Exception ex)
                {
                    transaction.Rollback();
                    ExceptionUtility.LogException(ex, "error");
                    throw ex;
                }
                finally
                {
                    // Attempt to commit the transaction.
                    transaction.Commit();

                    conn.Close();
                    conn.Dispose();
                    command.Dispose();
                }

小问题 - 你不应该在finally中尝试提交 - 相反,它应该在操作后的try中。 - Marc Gravell
可能有点过时了,但您能否确认我的答案解决了您的问题? - Afshin
2个回答

13

使用事务时,应该在任何地方都使用它。

    cmd.Transaction = transaction;

存储过程本身包含自己的事务,这会有影响吗? - pothios
所以问题是如何实现运行一个事务,该事务将调用具有自己事务的存储过程 :( - pothios
你不需要做任何特定的事情,只需让 .net 完成它的工作,尝试上面的代码,希望一切都会很好 :) - Afshin

2

使用连接字符串事务目前不太流行。您可以删除与SqlTransaction相关的所有内容,然后使用TransactionScope包装您的代码。


1
在使用TransactionScope时要非常小心。当它正常工作时,似乎很不错。但是我发现在针对非本地SQL服务器时,它非常脆弱。你需要把事情安排得“恰到好处”。 - Chris Rogers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接