Несколько обновлений БД: - PullRequest
2 голосов
/ 08 октября 2008

Заменяет Вопрос: Обновление нескольких строк в таблицу SQL

Вот фрагмент кода для обновления набора результатов экзамена. Структура БД такая же, как и у меня, но я могу представить хранимые процедуры для включения (что сложно изменить, поэтому я сохраняю это до конца).

Вопрос: есть ли лучший способ использования 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 ]

4 голосов
/ 09 октября 2008

Несколько вещей выделяются:

  • Вы не показываете, где создается экземпляр 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
}

Наконец, еще одна проблема заключается в том, что вы смешиваете код пользовательского интерфейса (например, Request.Form) с кодом доступа к данным. Было бы более модульным и тестируемым, чтобы отделить их - например, разделив ваше приложение на уровни пользовательского интерфейса, бизнес-логики и доступа к данным.

2 голосов
/ 09 октября 2008

Для 30 обновлений я думаю, что вы на правильном пути, хотя комментарий о необходимости использования около updateCommand является правильным.

Мы обнаружили, что лучший способ выполнения массовых обновлений (> 100 строк) - это использование класса SqlBulkCopy для временной таблицы с последующим вызовом хранимой процедуры для заполнения активной таблицы.

0 голосов
/ 08 октября 2008

Я вижу проблему, когда вы открываете соединение.

Я бы по крайней мере перед каждым обновлением вызывал открытие, а затем закрывал соединение после обновления.

Если выполнение вашего цикла занимает много времени, ваше соединение будет открыто в течение длительного времени.

Хорошее правило - никогда не открывать свою команду, пока она вам не понадобится.

0 голосов
/ 08 октября 2008

Вы можете массово вставить, используя OpenXML . Создайте XML-документ, содержащий все ваши вопросы и ответы, и используйте его для вставки значений.

Редактировать: Если вы придерживаетесь своего текущего решения, я бы по крайней мере завернул ваши SqlConnection и SqlCommand в блок использования, чтобы убедиться, что они утилизируются.

0 голосов
/ 08 октября 2008

выдает одно обновление, соответствующее таблице значений:

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

Это имеет то преимущество, что является ничем иным (например, если вы завернули несколько обновлений в транзакции) и будет работать быстрее, так как:

  • Таблица и связанные с ней индексы просматриваются / обновляются один раз
  • Вы платите только за задержку между вашим приложением и сервером базы данных один раз, а не за каждое обновление
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...