这个SqlTransaction已经完成;它不再可用,为什么?

时间:2017-03-10 11:34:21

标签: c# asp.net .net c#-4.0 ado.net

代码:

我正在尝试运行此函数,但它会抛出错误: 此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;
      }
   }
}

3 个答案:

答案 0 :(得分:3)

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

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="javascript.js"></script>

MSDN开始:

  

如果是,则Commit和Rollback都会生成InvalidOperationException   连接终止或事务已经滚动   回到服务器上。

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

答案 1 :(得分: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
        ...
    }
}

答案 2 :(得分:0)

如果以上答案不能解决您的问题,则您可能需要检查数据库和表的设置是否正确。

在某些情况下,缺少主键可能会导致与in this answer中所述的错误相同。