2013-10-31 72 views
0

我在c#中有此功能。當FOR被調用時,ExecuteNonQuery中會出現一個錯誤。錯誤是「ExecuteNonQuery需要該命令在分配給該命令的連接處於未決的本地事務中時纔有事務,該命令的Transaction屬性尚未初始化。」我如何使用c更新SQL#

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; 
        } 
       } 
+0

這是一個好習慣參數的所有SQL查詢,安全性和可讀性 –

+0

的原因有很多回答你的問題,但應該指出的是,這是總是在您的查詢中使用參數的好習慣,而不是僅僅合併字符串。 – SamiHuutoniemi

+0

儘管不是問題的一部分,但您可能需要考慮使用參數化查詢,而不是將sql文本拼接在一起。 Google Sql注入 –

回答

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; 
0

你忘了設置交易

comando.Transaction = trx; 
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(); 
0

您需要設置SqlCommand的事務屬性。

SqlCommand comando = new SqlCommand(); 
comando.Transaction = trx; 
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; 
    } 
} 
1

此錯誤消息表明,你已經打開了交易,它仍然是在執行ExecuteNonQuery點開放,

承諾之前,您正在執行ExecuteNonQuery的交易。

定義

comando.Transaction = trx; 

這樣的ExecuteNonQuery將在同一事務中執行。

0

正如已經指出的那樣,您絕不會將事務分配給命令。不過,我還提到了其他幾點。

首先和最重要的是使用參數化查詢,他們將提高性能,類型安全性,最重要的是從SQL Injection Attacks節省您。

所以不是:

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-服務器2008+可以使用Table valued Parameters爲此更新的一個查詢:

你首先需要一個類型

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,here is why)。所以,把他們放在一起,你會得到:

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(); 
}