Выбрать главу

 Dim result As Integer

 Dim records As Integer

 Dim SelectedYear As String

 ' Создание экземпляров объектов Connection и Command.

 Dim cnn As SqlConnection = New SqlConnection( _

  "server=localhost;uid=sa;database=novelty")

 Dim cmd As New SqlCommand()

 Dim trans As SqlTransaction

 ' Получение значения года.

 SelectedYear = lstYears.SelectedItem.ToString

 ' Размещение кода внутри блока Try-Catch для

 ' обработки исключительных ситуаций.

 Try

  ' Открытие объекта Connection и запуск транзакции.

  cnn.Open()

  trans = cnn.BeginTransaction

  ' Включение команды в транзакцию.

  cmd.Connection = cnn

  cmd.Transaction = trans

  ' Указание команды SQL для вставки соответствующих

  ' записей в архивную таблицу.

  sql = "SELECT * INTO tblOrder" & SelectedYear & _

   FROM tblOrder WHERE year (OrderDate) = " & SelectedYear

  ' Передача текста команды SQL в транзакцию.

  cmd.CommandText = sql

  result = cmd.ExecuteNonQuery()

  ' Отображение результатов вставки записей в архивную таблицу.

  If result > 0 Then

   records = result MessageBox.Show(records & _

    " records inserted successfully into tblOrder" & SelectedYear)

  Else

   MessageBox.Show( _

    "No records inserted into tblOrder" & SelectedYear)

   ' При отсутствии записей созданная таблица

   ' не нужна и транзакцию нужно откатить.

   trans.Rollback()

  End If

  If records > 0 Then

   ' Команда SQL для удаления соответствующих

   ' записей из текущей таблицы.

   sql = "delete FROM tblOrder WHERE year (OrderDate) = " _

    & SelectedYear

   ' Эта команда находится в той же транзакции.

   cmd.CommandText = sql

   result = cmd.ExecuteNonQuery()

   ' Показать результаты удаления записей.

   If result = records Then

    MessageBox.Show(records & _

     " records deleted successfully")

    ' Все действия успешно выполнены, можно фиксировать транзакцию.

    trans.Commit()

   Else

    MessageBox.Show("No records deleted!")

   End If

  Else

   ' Никаких действий.

  End If

 Catch ex As Exception

  ' Какие-то действия не выполнены, поэтому нужно

  ' отменить (откатить) всю транзакцию.

  Try

   ' Отображение сообщения об ошибке.

   MessageBox.Show(ex.Message & _

    ControlChars.CrLf & ControlChars.CrLf & _

    "Transaction Failed!")

   trans.Rollback()

  Catch ex2 As Exception

  End Try

 Finally

  cnn.Close()

 End Try

End Sub

Подпрограмма frmArchive_Load инициализирует список lstYears значениями, из которых можно выбрать год архивирования, и выбирает используемый по умолчанию год. Конечно, эту подпрограмму можно было бы усовершенствовать так, чтобы в списке отображались только те годы, для которых существуют записи о заказах. Однако для демонстрации принципов работы транзакций достаточно и такой подпрограммы.

Подпрограмма btnCancel_Click обработки щелчков мышью на кнопке Cancel просто закрывает форму, что в данном случае приводит к закрытию программы. Все необходимые действия выполняются обработчиком щелчков мышью на кнопке OK. После объявлений переменных следует получить выбранный год из списка lstYears и сохранить его для дальнейшего использования. Для гарантированной отмены транзакции в случае возникновения любой исключительной ситуации следует окружить активный код блоком Try-Catch-Finally.

Поскольку транзакции определяются на уровне подключения, то сначала нужно открыть подключение, а затем создать объект Transaction с помощью вызова метода BeginTransaction для открытого подключения. Объекты Connection и Transaction присваиваются объекту Command, который будет использоваться для выполнения команд по отношению к базе данных.

Первые два этапа создания архивной таблицы и копирования выбранных строк выполняются с помощью одной команды SELECT, которая содержит предложение INTO имя_таблицы. Указанная таким образом таблица создается автоматически, а если такая таблица уже существует, то генерируется исключительная ситуация. Выбранное значение года добавляется к имени таблицы tblOrder для создания имени новой архивной таблицы.

НА ЗАМЕТКУ

Команда SELECT INTO не создает индекс, если он существует в исходной таблице. Для повышения производительности выполнения запросов по отношению к данной таблице, вероятно, придется создать индексы по одному или нескольким полям.

Для выполнения команды SQL вызывается метод ExecuteNonQuery, который возвращает количество охваченных запросом записей. Если это возвращаемое значение больше нуля, следовательно, нужные записи найдены и вставлены в новую таблицу. В противном случае это значит, что таблица не может быть создана либо для копирования не найдено никаких записей. В любом из этих двух случаев транзакция откатывается, даже если таблица создана, чтобы база данных не наполнялась пустыми и бесполезными таблицами.

Если хотя бы одна запись скопирована в таблицу, то ее прототип в исходной таблице tblOrder удаляется с помощью команды DELETE, содержащей предложение WHERE с заданным годом. В случае успешного выполнения этой команды, т.e. если количество скопированных и удаленных строк совпадает, транзакция считается успешно завершенной и фиксируется. В противном случае, т.е. если какая-то отдельная операция завершится неудачно (нарушится процесс удаления записей, будет отменено разрешение на удаление архивируемых данных или произойдет сбой сервера), вся транзакция будет отвергнута. Откат транзакции гарантирует, что при неудачной попытке удаления корректных записей из таблицы tblOrder архивная таблица tblOrderХХХХ будет удалена.