2017-08-08 97 views
1

是否有任何方法來參數化插入多行的SQL INSERT語句(在C#中)?目前我能想到的只有一個辦法,來生成插入多張行的聲明,但也就是SQL注入相當開放:參數化多行插入

string sql = " INSERT INTO my_table" 
      + " (a, b, c)" 
      + " VALUES"; 

// Add each row of values to the statement 
foreach (var item in collection) { 
    sql = sql 
     + String.Format(" ({0}, {1}, {2}),", 
       aVal, bVal, cVal); 
} 

// Remove the excessive comma 
sql = sql.Remove(sql.Length - 1); 

什麼是做到這一點的聰明/更安全的方法是什麼?

+0

你可以參考[這個問題](https://stackoverflow.com/questions/7174792/does-using-parameterized-sqlcommand-make-my-program-immune-to-sql-injection)(其中OP正確使用參數化)和相應的答案。 –

+0

看看SqlBulkCopy類:https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy(v=vs.110).aspx,它提供了一種有效的批量加載方式數據轉換爲sql。 – Riv

+0

@RigertaDemiri我不明白我應該如何實現這一點,在我的確切情況?我在其他地方使用參數化,但僅在使用單行插入時使用。我如何在多行插入中使用它? – Noceo

回答

2

您可以添加PARAMATERS內循環,如:

using (var comm = new SqlCommand()) { 
     var counter = 0; 
     foreach (var item in collection) { 
      sql = sql + String.Format(" (@a{0}, @b{0}, @c{0})," counter); 

      comm.Parameters.AddWithValue("@a" + counter, aVal); 
      comm.Parameters.AddWithValue("@b" + counter, bVal); 
      comm.Parameters.AddWithValue("@c" + counter, cVal); 
      counter++; 
     } 
    } 

但我真的不會做多行插入這樣的。 IIRC查詢中參數的最大數量約爲2100,這可能會非常快速地變大。當你通過一個集合循環,無論如何,你可以只將其發送到數據庫中你的循環,是這樣的:

using (var con = new SqlConnection("connectionString here")) 
{ 
    con.Open(); 
    var sql = "INSERT INTO my_table (a, b, c) VALUES (@a,@b,@c);" 

    using (var comm = new SqlCommand(sql, con)) 
    { 
     comm.Parameters.Add("@a", SqlDbType.Int); 
     comm.Parameters.Add("@b", SqlDbType.NVarChar); 
     comm.Parameters.Add("@c", SqlDbType.Int); 
     foreach (var item in collection) { 
     { 
      comm.Parameters["@a"].Value = aVal; 
      comm.Parameters["@b"].Value = bVal; 
      comm.Parameters["@b"].Size = bVal.Length; 
      comm.Parameters["@c"].Value = cVal; 

      comm.ExecuteNonQuery(); 
     } 
    } 
} 

該語句只准備了一次(而不是一個巨大的語句的參數100的更快) ,並且它在一條記錄失敗時不會失敗所有記錄(爲此添加一些異常處理)。如果你想在一個記錄失敗時全部失敗,你可以把它包裝在一個事務中。

+0

這是一個替代建議,但也許不是一個壞主意。我100%確定這會如何影響性能,但很可能這不是問題。 – Noceo

+0

一次爲多個記錄添加變體。我仍然不會那樣做:) – Stephen

+0

一個問題:如果我使用'try','catch'和'finally',在'finally'語句中有'con.Close()'的地方。然後在什麼級別上運行'con.Open()'? – Noceo