【问题标题】:This SqlTransaction has completed; it is no longer usable, why?此 SqlTransaction 已完成;已经不能用了,为什么?
【发布时间】:2017-03-10 11:34:20
【问题描述】:

代码:

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

【问题讨论】:

  • 在我看来你在提交事务之前关闭了连接
  • 您可能也应该将您的连接放在using 块中。
  • catch 块也是多余的。 using 块将回滚处理事务。
  • 你为什么要使用事务?你只执行一个程序
  • 另外,连接也应该放在using 语句中。现在,任何错误都会使连接保持打开状态

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


【解决方案1】:

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

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

来自MSDN

如果提交和回滚都会生成 InvalidOperationException 连接被终止或者事务已经滚动 回到服务器上。

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

【讨论】:

  • 我怀疑它会被提交。如果在这种情况下回滚会更有意义。
  • @Evk 我同意,这是不正确的措辞。我已经修改了答案以消除可能的误导。
  • 如果你写关闭连接回滚所有以connection.BeginTransaction开始的未决事务会更清楚:)
【解决方案2】:

如果连接关闭,您将无法回滚或提交事务。当连接关闭时,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
        ...
    }
}

【讨论】:

    【解决方案3】:

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

    在某些情况下,缺少主键会产生与in this answer 所述相同的错误。

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 2020-01-19
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2014-11-17
      • 1970-01-01
      相关资源
      最近更新 更多