2012-12-06 129 views
1

我想从我的代码中删除手动转义。取而代之,我想使用SqlParameter对象。如何在循环中添加SqlParameters?

foreach (ThreadPost post in ThreadPosts) 
{ 
    string newMessage = Clean(post.Message); 
    string oldMessage = post.Message; 

    // escape ' character for prevent errors in SQL script 
    // I want to pass newMessage and oldMessage as an SqlParameters to prevent unexpected changes, but how it could be done based on the code bellow??? 
    newMessage = newMessage.Replace("'", "''"); 
    oldMessage = oldMessage.Replace("'", "''"); 

    cmdText += string.Format("INSERT INTO ThreadCleanup VALUES ({0}, {1}, '{2}', '{3}')", 
      post.ID.ToString(), 
      "NULL", 
      oldMessage, 
      newMessage); 
    } 
} 
if (!string.IsNullOrEmpty(cmdText)) 
{ 
    using (SqlConnection con = new SqlConnection(CONNSTR)) 
    { 
      con.Open(); 
      SqlTransaction tran = con.BeginTransaction(IsolationLevel.ReadUncommitted); 
      try 
      { 
       using (SqlCommand cmd = new SqlCommand(cmdText, con, tran)) 
       { 
       cmd.ExecuteNonQuery(); // updated records 
       } 
       tran.Commit(); 
      } 
      catch (SqlException ex) 
      { 
       tran.Rollback(); 
      } 
      con.Close(); 
    } 
} 
+0

[你有什么尝试](http://whathaveyoutried.com)?请解释你卡在哪里。 – Oded

+0

我不想做Replace(“'”,“''”)。而不是我想要使用SqlParameters来添加newMessage和oldMessage命令。 – Vytalyi

+0

是的,我明白你_want_。我在问你是什么**尝试**。 – Oded

回答

1

你可以做到这一点大概你现在做同样的方式 - 通过在一个循环的格式insert,但不是每次使用新/老对一个插件,使用一个语句都对。您应该明确地使用列名,以避免依赖表中的列顺序(生产中很大的否定),并避免在循环中创建第二个参数,即使您始终向其发送NULL

var cmdText = new StringBuilder("INSERT INTO ThreadCleanup (id,oldMessage,newMessage) VALUES "); 
var args = new List<Tuple<long,string,string>>(); 
foreach (ThreadPost post in ThreadPosts) { 
    int cnt = args.Count(); 
    if (cnt != 0) { 
     cmdText.Append(","); 
    } 
    cmdText.AppendFormat("(@id{0}, @old{0}, @new{0})", cnt); 
    args.Add(new Tuple<long,string,string>(post.ID, post.Message, Clean(post.Message))); 
} 

在这一点上,你有一个SQL字符串,它看起来像这样:

INSERT INTO ThreadCleanup (id,oldMessage,newMessage) VALUES 
(@id0, @old0, @new0), (@id1, @old1, @new1), (@id2, @old2, @new2), ... 

您也可以为每个参数的Tuple<long,string,string>列表,所以你可以这样做:

if (args.Count != 0) { 
    using (SqlConnection con = new SqlConnection(CONNSTR)) { 
     con.Open(); 
     SqlTransaction tran = con.BeginTransaction(IsolationLevel.ReadUncommitted); 
     try { 
      using (SqlCommand cmd = new SqlCommand(cmdText, con, tran)) { 
       for (var i = 0 ; i != args.Count ; i++) { 
        cmd.Parameters.AddWithValue("@id"+i, args[i].Item1); 
        cmd.Parameters.AddWithValue("@old"+i, args[i].Item2); 
        cmd.Parameters.AddWithValue("@new"+i, args[i].Item3); 
       } 
       cmd.ExecuteNonQuery(); // updated records 
      } 
      tran.Commit(); 
     } catch (SqlException ex) { 
      tran.Rollback(); 
     } 
     con.Close(); 
    } 
} 

一次做到这一点的好处是,无论您必须插入多少条记录,您都可以对数据库进行一次往返。除此之外,解决方案遵循与现有解决方案相同的模式,因此性能应具有可比性。

+0

谢谢您的详细解答! – Vytalyi

1

声明你的插入命令在foreach循环之外。 然后将SQLParameters添加到该命令。

String cmdInsert= "INSERT INTO ThreadCleanup VALUES(@value1,@value2,@value3,@value4)" 
     cmdInsert.Parameters.AddWithValue("@value1", System.Data.SqlDbType.VarChar); 
     cmdInsert.Parameters.AddWithValue("@value2", System.Data.SqlDbType.VarChar); 
     cmdInsert.Parameters.AddWithValue("@value3", System.Data.SqlDbType.VarChar); 
     cmdInsert.Parameters.AddWithValue("@value4", System.Data.SqlDbType.VarChar); 

然后在foreach循环中分配值。

foreach (ThreadPost post in ThreadPosts) 
{ 
string newMessage = Clean(post.Message); 
string oldMessage = post.Message; 

// escape ' character for prevent errors in SQL script 
// I want to pass newMessage and oldMessage as an SqlParameters to prevent unexpected changes, but how it could be done based on the code bellow??? 
newMessage = newMessage.Replace("'", "''"); 
oldMessage = oldMessage.Replace("'", "''"); 

cmdInsert.Parameters["@value1"].Value = post.ID.ToString(); 
cmdInsert.Parameters["@value2"].Value = DBNull.Value; 
cmdInsert.Parameters["@value3"].Value = oldMessage; 
cmdInsert.Parameters["@value4"].Value = newMessage; 

} 
+0

它看起来不错,你觉得如果我有10K的记录会减慢吗? – Vytalyi

+0

这是动态向SQLParameters添加值的方法。由于每次您的值都会发生更改,因此您无法使用AddWithValue()添加这些值。我认为所花费的时间将与您的foreach循环的运行时间大致相同。 – SKJ

1

类型 sqlcmd.Parameters.Clear(); sqlcmd.Parameters.AddWithValue(“@sample”,sample)之前的 ;