0

我在c#中有这个功能。调用 FOR 时,ExecuteNonQuery 中出现错误。错误是“当分配给命令的连接处于挂起的本地事务中时,ExecuteNonQuery 要求命令具有事务。命令的事务属性尚未初始化。”

SqlConnection cnn = new SqlConnection(WebConfigurationManager.ConnectionStrings["strCnn"].ToString());
                cnn.Open();
                SqlTransaction trx = cnn.BeginTransaction();

                try
                {

                    SqlCommand cmd= new SqlCommand();

                    for (int j = 0; j < arr.Length; j++) {
                        cmd.CommandText = "UPDATE rc SET nc= " +  arr[j].Col3 + " WHERE cr = " + arr[j].Col1;
                        cmd.Connection = cnn;
                        cmd.ExecuteNonQuery();
                    }

                    trx.Commit();
                    return 1;
                }
                catch (SqlException ex)
                {
                    try
                    {
                        trx.Rollback();
                        return 0;
                    }
                    catch (Exception exRollback)
                    {
                        return 0;
                    }  
                }
4

7 回答 7

1

此错误消息表明您已经打开了一个事务,并且在执行时它仍然处于打开状态ExecuteNonQuery

ExecuteNonQuery在交易承诺之前执行。

定义

comando.Transaction = trx;

这样 ExecuteNonQuery 将在同一事务上执行。

于 2013-10-31T11:07:04.793 回答
0

您的 sqlCommand 不知道您的事务。

这是一个复制粘贴修复:

SqlConnection conexao = new SqlConnection(WebConfigurationManager.ConnectionStrings["strConexao"].ToString());
conexao.Open();
SqlTransaction trx = conexao.BeginTransaction();

try
{
    for (int j = 0; j < arr.Length; j++) {
        var commandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " +  arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;
        SqlCommand comando = new SqlCommand(commandText, conexao, trx);
        comando.ExecuteNonQuery();
    }

    trx.Commit();
    return 1;
}
catch (SqlException ex)
{
    try
    {
        trx.Rollback();
        return 0;
    }
    catch (Exception exRollback)
    {
        return 0;
    }  
}
于 2013-10-31T11:00:18.173 回答
0

你忘了设置交易

 comando.Transaction = trx;
于 2013-10-31T10:57:47.910 回答
0

您需要将事务分配给命令,如下所示:

SqlCommand comando = new SqlCommand();
comando.Transaction = trx;

我还建议Connection在 for 循环之外设置属性,因此您的代码将如下所示:

SqlCommand comando = new SqlCommand();
comando.Transaction = trx;
comando.Connection = conexao;

for (int j = 0; j < arr.Length; j++) {
    comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " +  arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;
    comando.ExecuteNonQuery();
}

trx.Commit();
于 2013-10-31T10:57:50.630 回答
0

您需要设置SqlCommand的交易属性。

 SqlCommand comando = new SqlCommand();
 comando.Transaction = trx;
于 2013-10-31T10:58:03.787 回答
0

正如已经指出的那样,您永远不会将您的事务分配给命令。但是,我还提到了其他几点。

首先,最重要的是使用参数化查询,它们将提高性能、类型安全性,最重要的是让您免受SQL 注入攻击

所以而不是:

comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = " +  arr[j].Col3 + " WHERE CD_RECURSO = " + arr[j].Col1;

你会使用:

comando.CommandText = "UPDATE RECURSO_CLIENTE SET NM_CLIENTE = @Col3 WHERE CD_RECURSO = @Col1";
comando.Parameters.AddWithValue("@Col3", arr[j].Col3);
comando.Parameters.AddWithValue("@Col1", arr[j].Col1);

其次,用包装器包装你的 sql 命令对象using以确保它被正确处理,一遍又一遍地重用同一个对象没有任何好处(这可能会导致问题):

for (int j = 0; j < arr.Length; j++) 
{
    using (var comando = new SqlCommand("UPDATE RECURSO_CLIENTE SET NM_CLIENTE = @Col3 WHERE CD_RECURSO = @Col1", conexao))
    {
        comando.Transaction = trx;
        comando.Parameters.AddWithValue("@Col3", arr[j].Col3);
        comando.Parameters.AddWithValue("@Col1", arr[j].Col1);
        comando.ExecuteNonQuery();
    }
}

最后,如果您使用的是 SQL-Server 2008+,您可以使用表值参数在单个查询中执行此更新:

你首先需要一个类型

CREATE TABLE YourTypeName AS TABLE (Col1 INT, Col3 INT);

那么您的更新语句将类似于:

DECLARE @UpdateValues AS YourTypeName;

MERGE RECURSO_CLIENTE rc
USING @UpdateValues u
    ON rc.CD_RECURSO = u.Col1
WHEN MATCHED UPDATE
    SET NM_CLIENTE = u.Col3;

这意味着单个语句,您不需要使用显式事务。(您可能想知道为什么我使用合并而不是 UPDATE,这就是为什么)。所以把它们放在一起你会得到:

var dataTable = new DataTable();
dataTable.Columns.Add("Col1", typeof(int));
dataTable.Columns.Add("Col3", typeof(int));

for (int j = 0; j < arr.Length; j++) 
{
    var newRow = dataTable.NewRow();
    newRow[0] = arr[j].Col1;
    newRow[1] = arr[j].Col3;
    dataTable.Rows.Add(newRow);
}

string sql = @" MERGE RECURSO_CLIENTE rc
                USING @UpdateValues u
                    ON rc.CD_RECURSO = u.Col1
                WHEN MATCHED UPDATE
                    SET NM_CLIENTE = u.Col3;";

using (var conexao = new SqlConnection(WebConfigurationManager.ConnectionStrings["strConexao"].ToString()))
using (var comando = new SqlCommand(sql, conexao))
{
    conexao.Open(); 
    var tableParam = new SqlParameter("@UpdateValues", SqlDbType.Structured);
    tableParam.TypeName = "@YourTypeName";
    tableParam.Value = dataTable;
    comando.Parameters.Add(tableParam);
    comando.ExecuteNonQuery();
}
于 2013-10-31T11:21:21.633 回答
0

利用

// Create command on transaction and automatically assign open transaction
var comando = conexao.CreateCommand()

或将事务分配给命令。

// Create command
var comando = new SqlCommand();
// and assign transaction manually
comando.Transaction = trx;
于 2013-10-31T10:56:50.030 回答