c# - 如何在循环中添加SqlParameters?

标签 c# sql-server-2008 ado.net

我想从我的代码中删除手动转义。相反,我想使用 SqlParameter 对象。

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

最佳答案

您可以按照与现在大致相同的方式进行操作 - 通过格式化 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();
    }
}

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

关于c# - 如何在循环中添加SqlParameters?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13741879/

相关文章:

c# - 如何在没有任何闪烁的情况下将 pictureBox 移动到已绘制的面板上?

c# - 如何获取和设置 EmguCV Mat 图像的像素值?

sql - 具有许多空值的表与 2 个单独的表

c# - DataAdapter.Fill 性能异常

c# - 当我需要使用带有多个参数的 POST 方法而不是单独的模型时?

c# - 使用 OpenTK/MonoTouch 从顶点列表中绘制?

SQL Server 2008 报告 : Sum of Max of group

sql-server - 无法获取有关 Windows NT 组/用户的信息

ado.net - 如何在不使用数据表(C#)的情况下以字符串形式返回单个 sql 结果?

c# - 从列 = 任何值的表中选择