2017-08-08 36 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