这个 SqlTransaction 已经完成,不能再使用了,为什么?

3

代码:

我尝试运行这个函数,但它会抛出错误: 这个 SqlTransaction 已经完成;它不再可用。

我已经尝试了其他所有方法但都没有奏效。我已经在不使用USING的情况下使用它,但仍然出现相同的错误。

为什么会这样呢?

public Boolean AddWorkProgress(int WorkID, int ContractorID, float PhysicalProgress, 
  decimal FinancialProgress, int UserID, int OrgID, float FinancialProgressPecentage)
{
   SqlCommand SqlCom = new SqlCommand("AddWorkProgress", DataBaseConnection.OpenConnection());
   SqlCom.CommandType = CommandType.StoredProcedure;

   using (SqlTransaction sqlTrans = SqlCom.Connection.BeginTransaction()) 
   {
      SqlCom.Transaction = sqlTrans;

      try
      {
         SqlCom.Parameters.AddWithValue("@Work_ID", WorkID);
         SqlCom.Parameters.AddWithValue("@Contractor_ID", ContractorID);
         SqlCom.Parameters.AddWithValue("@PhysicalProgress", PhysicalProgress);
         SqlCom.Parameters.AddWithValue("@FinancialProgress", FinancialProgress);
         SqlCom.Parameters.AddWithValue("@OrgID", OrgID);
         SqlCom.Parameters.AddWithValue("@fk_WebUsers_UserID", UserID);
         SqlCom.Parameters.AddWithValue("@FinancialProgressPercentage", FinancialProgressPecentage);
         SqlParameter SqlParamReturnStatus = new SqlParameter("@ReturnStatus", SqlDbType.Bit);
         SqlCom.Parameters.Add(SqlParamReturnStatus);
         SqlParamReturnStatus.Direction = ParameterDirection.Output;
         SqlParameter SqlParamReturnStatusMessage = new SqlParameter("@ReturnStatusMessage", SqlDbType.VarChar, -1);
         SqlCom.Parameters.Add(SqlParamReturnStatusMessage);
         SqlParamReturnStatusMessage.Direction = ParameterDirection.Output;
         SqlCom.ExecuteNonQuery();
         DataBaseConnection.CloseConnection();

         string ReturnStatusMessage = Convert.ToString(SqlParamReturnStatusMessage);
         Boolean ReturnStatus = Convert.ToBoolean(SqlParamReturnStatus.Value);
         // ProgressID = Convert.ToInt64(SqlParamReturnProgressID.Value);

         sqlTrans.Commit();
         return ReturnStatus;
      }

      catch (Exception ex)
      {
         sqlTrans.Rollback();
         sqlTrans.Dispose();

         throw ex;
      }
   }
}

1
看起来你在提交事务之前关闭了连接。 - Dave Becker
1
你应该将你的连接也放在一个using块中。 - David
catch块也是多余的。using块将会回滚并释放事务。 - Panagiotis Kanavos
为什么你要使用事务呢?你只执行了一个存储过程。 - Fabio
此外,连接也应该放在一个using语句中。目前,任何错误都会导致连接保持打开状态。 - Panagiotis Kanavos
顺便说一下,关闭连接但不提交事务将导致回滚。当调用CloseConnection()时,无论存储过程执行了什么操作,都会消失。 - Panagiotis Kanavos
3个回答

4

您在提交事务之前关闭了连接:

DataBaseConnection.CloseConnection();
// skipped code
sqlTrans.Commit();

来自MSDN

如果连接已终止或事务在服务器上已回滚,则提交和回滚都会生成InvalidOperationException。

这正是您的情况 - 在提交/回滚事务之前连接被关闭了。


我怀疑它会被提交。如果是这种情况,回滚会更有意义。 - Evk
@Evk 我同意,那个措辞是不正确的。我已经修改了答案,以消除可能的误导。 - Andrey Korneyev
如果你写上关闭连接会回滚所有使用connection.BeginTransaction开始的未完成事务,那就更清楚了 :) - Evk

0
如果上述答案不能解决您的问题,那么您可能需要检查一下数据库和表是否设置正确。
在某些情况下,缺少主键可能会导致与此答案中描述的相同错误。

0

如果连接关闭,就无法回滚或提交事务。当连接关闭时,SQL Server会自动回滚任何未完成的事务。

catch块也是多余的。事务在被处理掉后会自动回滚,除非调用了Commit()

最后,连接的处理方式不安全。如果在CloseConnection()之前发生任何错误,连接将保持打开状态。

正确使用连接和事务可以大大简化代码:

var SqlCom = new SqlCommand("AddWorkProgress");
SqlCom.CommandType = CommandType.StoredProcedure;
//... prepare the command. No need to use a connection

using(var connection=DataBaseConnection.OpenConnection())
using(var transaction= connection.BeginTransaction()) 
{
    SqlCom.Connection=connection;
    SqlCom.Transaction=transaction;

    SqlCom.ExecuteNonQuery();
    transaction.Commit();

    //Process the results
}

就是这样。当using块完成时,连接将关闭。如果没有调用Commit(),事务将被回滚,这只会在发生错误的情况下发生。

一旦你将存储过程的构建与执行分开,你可以进一步简化代码。例如,你可以在类或应用程序初始化时仅创建一次命令。每次你想要执行它时,只需设置连接和参数值,例如:

public Boolean AddWorkProgress(int WorkID, int ContractorID, float PhysicalProgress, decimal FinancialProgress, int UserID, int OrgID, float FinancialProgressPecentage)
{
    using(var connection=DataBaseConnection.OpenConnection())
    using(var transaction= connection.BeginTransaction()) 
    {
        _addProgressCmd.Parameters["@Work_ID"].Value=WorkID;
        ....
        _addProgressCmd.Connection=connection;
        _addProgressCmd.Transaction=transaction;

        _addProgressCmd.ExecuteNonQuery();
        transaction.Commit();

        var status=(bool)_addProgressCmd.Parameters["@ReturnStatus"].Value;
        var statusMsg=(string)_addProgressCmd.Parameters["@ReturnStatusMessage"].Value;

        //Process the results
        ...
    }
}

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