多个数据库更新:

时间:2008-10-08 19:33:12

标签: c# .net sql-server

取代问题:Update multiple rows into SQL table

以下是更新考试成绩集的代码段。 数据库结构是给定的,但我可以提交存储过程(这是一个很难修改,所以我保存到最后。)

问题:是否有更好的方法使用SQL Server v 2005.,net 2.0?

string update = @"UPDATE dbo.STUDENTAnswers 
                              SET ANSWER=@answer
                              WHERE StudentID =@ID and QuestionNum =@qnum";
            SqlCommand updateCommand = new SqlCommand( update, conn );
            conn.Open();

            string uid = Session["uid"].ToString();
            for (int i= tempStart; i <= tempEnd; i++)
            {
                updateCommand.Parameters.Clear();
                updateCommand.Parameters.AddWithValue("@ID",uid);
                updateCommand.Parameters.AddWithValue("@qnum",i);
                updateCommand.Parameters.AddWithValue("@answer", Request.Form[i.ToString()]);
                try
                {
                    updateCommand.ExecuteNonQuery();
                }
                catch { }
            }

5 个答案:

答案 0 :(得分:4)

有些事情很突出:

  • 您没有显示SqlConnection的实例化位置,因此您无法正确处理它。

  • 你不应该吞下循环中的异常 - 最好在顶级异常处理程序中处理它们。

  • 您通过循环在每次迭代中实例化新参数 - 您可以重复使用这些参数。

将它放在一起它可能看起来像下面这样(如果你不想使用一个事务,即不关心是否有一些但不是所有的更新都成功):

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlCommand updateCommand = new SqlCommand(update, conn))
    {
        string uid = Session["uid"].ToString();
        updateCommand.Parameters.AddWithValue("@ID", uid);
        updateCommand.Parameters.AddWithValue("@qnum", i);
        updateCommand.Parameters.Add("@answer", System.Data.SqlDbType.VarChar);
        for (int i = tempStart; i <= tempEnd; i++)
        {
            updateCommand.Parameters["@answer"] = Request.Form[i.ToString()];
            updateCommand.ExecuteNonQuery();
        }
    }
}

或者使用交易来确保全部或全部:

using (SqlConnection conn = new SqlConnection(connectionString))
{
    conn.Open();
    using (SqlTransaction transaction = conn.BeginTransaction())
    {
        using (SqlCommand updateCommand = new SqlCommand(update, conn, transaction))
        {
            string uid = Session["uid"].ToString();
            updateCommand.Parameters.AddWithValue("@ID", uid);
            updateCommand.Parameters.AddWithValue("@qnum", i);
            updateCommand.Parameters.Add("@answer", System.Data.SqlDbType.VarChar);
            for (int i = tempStart; i <= tempEnd; i++)
            {
                updateCommand.Parameters["@answer"] = Request.Form[i.ToString()];
                updateCommand.ExecuteNonQuery();
            }
            transaction.Commit();
        }
    } // Transaction will be disposed and rolled back here if an exception is thrown
}

最后,另一个问题是您正在将UI代码(例如Request.Form)与数据访问代码混合在一起。将它们分开是更模块化和可测试的 - 例如通过将您的应用程序拆分为UI,业务逻辑和数据访问层。

答案 1 :(得分:2)

对于30次更新,我认为您已走上正轨,但有关使用约updateCommand的需求的评论是正确的。

我们发现执行批量更新(&gt; 100行)的最佳效果是通过SqlBulkCopy类到临时表,然后是存储过程调用来填充实时表。

答案 2 :(得分:0)

我看到的问题是您打开连接时的问题。

我至少会在每次更新之前调用open,然后在更新后关闭连接。

如果你的循环需要时间来执行,你的连接将会打开很长时间。

在您需要之前永远不要打开命令是一个很好的规则。

答案 3 :(得分:0)

您可以使用OpenXML批量插入。创建一个包含所有问题和答案的xml文档,并使用它来插入值。

编辑:如果您坚持使用当前的解决方案,我至少会将您的SqlConnection和SqlCommand包装在一个使用块中,以确保它们被处理掉。

答案 4 :(得分:-1)

发出一个与值表相对应的更新:

UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (
  SELECT 1 as q, 'answer1' as a
  UNION ALL SELECT 2, 'answer2' -- etc...
) x ON s.QuestionNum=x.q AND StudentID=@ID

所以你就这样把它放在一起:

using(SqlCommand updateCommand = new SqlCommand()) {
  updateCommand.CommandType = CommandType.Text;
  updateCommand.Connection = conn;
  if (cn.State != ConnectionState.Open) conn.Open();

  StringBuilder sb = new StringBuilder("UPDATE s SET ANSWER=a FROM dbo.STUDENTAnswers s JOIN (");
  string fmt = "SELECT {0} as q, @A{0} as a";
  for(int i=tempStart; i<tempEnd; i++) {
    sb.AppendFormat(fmt, i);
    fmt=" UNION ALL SELECT {0},@A{0}";
    updateCommand.Parameters.AddWithValue("@A"+i.ToString(), Request.Form[i.ToString()]);
  }
  sb.Append(") x ON s.QuestionNum=x.q AND StudentID=@ID");
  updateCommand.CommandText = sb.ToString();
  updateCommand.Parameters.AddWithValue("@ID", uid);
  updateCommand.ExecuteNonQuery();
}

这样做的好处是可以进行所有其他操作(例如,如果您在事务中包装了多个更新),并且运行速度更快:

  • 查看/更新表及相关索引
  • 您只需为应用程序和数据库服务器之间的延迟付费一次,而不是每次更新