Поделиться через


Пошаговое руководство. Обработка исключения параллельности

Исключения совместного доступа (DBConcurrencyException) вызываются, когда два пользователя пытаются одновременно изменить одни и те же данные в базе данных. В этом пошаговом руководстве создается приложение Windows, описывающее перехват DBConcurrencyException, поиск строки, вызвавшей ошибку, и одну стратегия, которую можно использовать для его обработки.

В данном пошаговом руководстве необходимо выполнить следующий процесс:

  1. Создать новый проект Приложение Windows.

  2. Создать новый набор данных на основе таблицы Customers базы данных "Борей".

  3. Создать форму с DataGridView для отображения данных.

  4. Заполнить набор данных данными из таблицы Customers базы данных "Борей".

  5. После заполнения набора данных необходимо использовать Визуальные инструменты для баз данных в Visual Studio для непосредственного доступа к таблице данных Customers и изменения записи.

  6. Затем в форме изменить значение в той же записи на другое, обновить набор данных и попытаться записать изменения в базу данных, что приведет к ошибке совместного доступа.

  7. Перехватить ошибку, а затем отобразить различные версии записей, предоставляя пользователю возможность продолжить обновление базы данных, либо отменить его.

Обязательные компоненты

Для выполнения этого пошагового руководства потребуется следующее.

Примечание

Отображаемые диалоговые окна и команды меню могут отличаться от описанных в справке в зависимости от текущих настроек или выпуска.Чтобы изменить параметры, выберите в меню Сервис пункт Импорт и экспорт параметров.Дополнительные сведения см. в разделе Работа с параметрами.

Создание нового проекта

Пошаговое руководство начинается с создания нового приложения Windows.

Чтобы создать проект приложения Windows

  1. Из меню Файл создайте новый проект.

  2. Выберите язык программирования в области Типы проектов.

  3. Выберите Приложение Windows в области Шаблоны.

  4. Назовите проект ConcurrencyWalkthrough и нажмите кнопку OK.

    Visual Studio добавит проект в Обозреватель решений и откроет новую форму в конструкторе.

Создание набора данных в базе данных "Борей"

В этом разделе создается набор данных с именем NorthwindDataSet.

Чтобы создать NorthwindDataSet

  1. В меню Данные выберите Добавить новый источник данных.

    Откроется окно мастер настройки источника данных.

  2. На странице Выбор типа источника данных выберите База данных.

  3. Выберите подключение к образцу базы данных "Борей" из списка доступных подключений или нажмите кнопку Создать подключение, если подключение недоступно в списке подключений.

    Примечание

    Если вы подключаетесь к файлу локальной базы данных, выберите Нет в ответ на вопрос о том, необходимо ли добавить файл в проект.

  4. Нажмите Далее на странице Сохранение подключения в файле конфигурации приложения.

  5. Разверните узел Таблицы и выберите таблицу Customers. По умолчанию набор данных должен называться NorthwindDataSet.

  6. Нажмите кнопку Готово, чтобы добавить набор данных в проект.

Создание элемента управления с привязкой к данным DataGridView

В этом разделе создается DataGridView путем перетаскивания элемента Customers из окна Источники данных на форму Windows Form.

Чтобы создать элемент управления DataGridView, привязанный к таблице Customers

  1. Выберите Показать Источники данных в меню Данные для открытия окна Источники данных.

  2. В окне Источники данных разверните узел NorthwindDataSet и выберите таблицу Customers.

  3. Щелкните стрелку вниз на узле таблицы и выберите DataGridView из раскрывающегося списка.

  4. Перетащите таблицу в пустую область формы.

    Элемент управления DataGridView с именем CustomersDataGridView и BindingNavigator с именем CustomersBindingNavigator добавляются на форму, связанную с BindingSource, который, в свою очередь, связан с таблицей в Customers NorthwindDataSet.

Контрольная точка

Теперь можно проверить форму, чтобы убедиться, что она ведет себя, как ожидалось до сих пор.

Чтобы проверить форму, выполните следующие действия:

  1. Нажмите клавишу F5 для запуска приложения.

    Появится форма с элементом управления DataGridView, заполненным данными из таблицы Customers.

  2. В меню Отладка выберите команду Остановить отладку.

Обработка ошибок совместного доступа

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

Приложение предоставляет пользователю три версии записи:

  • Текущая запись в базе данных.

  • Исходная запись, загруженная в набор данных.

  • Предлагаемые изменения в наборе данных.

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

Чтобы включить обработку ошибок совместного доступа

  1. Создайте пользовательский обработчик ошибок.

  2. Отобразите пользователю варианты выбора.

  3. Обработайте ответ пользователя.

  4. Отправьте обновления или сбросьте данные в наборе данных.

Добавление кода обработки исключений совместного доступа

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

В этом разделе добавляется код, который будет пытаться обновить базу данных и обработать все DBConcurrencyException, которые могут возникать, а также любые другие исключения.

Примечание

Методы CreateMessage и ProcessDialogResults будут добавлены позже в этом пошаговом руководстве.

Чтобы добавить обработку ошибок совместного доступа

  1. Добавьте следующий код под методом Form1_Load:

    Private Sub UpdateDatabase()
    
        Try
            Me.CustomersTableAdapter.Update(Me.NorthwindDataSet.Customers)
            MsgBox("Update successful")
    
        Catch dbcx As Data.DBConcurrencyException
            Dim response As Windows.Forms.DialogResult
    
            response = MessageBox.Show(CreateMessage(CType(dbcx.Row, NorthwindDataSet.CustomersRow)),
                "Concurrency Exception", MessageBoxButtons.YesNo)
    
            ProcessDialogResult(response)
    
        Catch ex As Exception
            MsgBox("An error was thrown while attempting to update the database.")
        End Try
    End Sub
    
    private void UpdateDatabase()
    {
        try
        {
            this.customersTableAdapter.Update(this.northwindDataSet.Customers);
            MessageBox.Show("Update successful");
        }
        catch (DBConcurrencyException dbcx)
        {
            DialogResult response = MessageBox.Show(CreateMessage((NorthwindDataSet.CustomersRow)
                (dbcx.Row)), "Concurrency Exception", MessageBoxButtons.YesNo);
    
            ProcessDialogResult(response);
        }
        catch (Exception ex)
        {
            MessageBox.Show("An error was thrown while attempting to update the database.");
        }
    }
    
  2. Замените метод CustomersBindingNavigatorSaveItem_Click для вызова метода UpdateDatabase, чтобы он выглядел следующим образом:

    Private Sub CustomersBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CustomersBindingNavigatorSaveItem.Click
        UpdateDatabase()
    End Sub
    
    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateDatabase();
    }
    

Отображение вариантов выбора

Только что написанный код вызывает процедуру CreateMessage для отображения пользователю сведений об ошибке. В рамках настоящего пошагового руководства окно сообщений используется для отображения пользователю различных версий записи и предоставления выбора: перезаписать запись с новыми изменениями или отменить изменения. Когда пользователь выбирает параметр (нажимает кнопку) в окне сообщения, ответ передается методу ProcessDialogResult.

Чтобы создать сообщение для отображения пользователю

  • Создайте сообщение, добавив следующий код в Редактор кода. Введите этот код под методом UpdateDatabase.

    Private Function CreateMessage(ByVal cr As NorthwindDataSet.CustomersRow) As String
        Return "Database: " & GetRowData(GetCurrentRowInDB(cr), 
                                         Data.DataRowVersion.Default) & vbCrLf &
               "Original: " & GetRowData(cr, Data.DataRowVersion.Original) & vbCrLf &
               "Proposed: " & GetRowData(cr, Data.DataRowVersion.Current) & vbCrLf &
               "Do you still want to update the database with the proposed value?"
    End Function
    
    
    '--------------------------------------------------------------------------
    ' This method loads a temporary table with current records from the database
    ' and returns the current values from the row that caused the exception.
    '--------------------------------------------------------------------------
    Private TempCustomersDataTable As New NorthwindDataSet.CustomersDataTable
    
    Private Function GetCurrentRowInDB(
        ByVal RowWithError As NorthwindDataSet.CustomersRow
        ) As NorthwindDataSet.CustomersRow
    
        Me.CustomersTableAdapter.Fill(TempCustomersDataTable)
    
        Dim currentRowInDb As NorthwindDataSet.CustomersRow =
            TempCustomersDataTable.FindByCustomerID(RowWithError.CustomerID)
    
        Return currentRowInDb
    End Function
    
    
    '--------------------------------------------------------------------------
    ' This method takes a CustomersRow and RowVersion 
    ' and returns a string of column values to display to the user.
    '--------------------------------------------------------------------------
    Private Function GetRowData(ByVal custRow As NorthwindDataSet.CustomersRow,
        ByVal RowVersion As Data.DataRowVersion) As String
    
        Dim rowData As String = ""
    
        For i As Integer = 0 To custRow.ItemArray.Length - 1
            rowData &= custRow.Item(i, RowVersion).ToString() & " "
        Next
    
        Return rowData
    End Function
    
    private string CreateMessage(NorthwindDataSet.CustomersRow cr)
    {
        return
            "Database: " + GetRowData(GetCurrentRowInDB(cr), DataRowVersion.Default) + "\n" +
            "Original: " + GetRowData(cr, DataRowVersion.Original) + "\n" +
            "Proposed: " + GetRowData(cr, DataRowVersion.Current) + "\n" +
            "Do you still want to update the database with the proposed value?";
    }
    
    
    //--------------------------------------------------------------------------
    // This method loads a temporary table with current records from the database
    // and returns the current values from the row that caused the exception.
    //--------------------------------------------------------------------------
    private NorthwindDataSet.CustomersDataTable tempCustomersDataTable = 
        new NorthwindDataSet.CustomersDataTable();
    
    private NorthwindDataSet.CustomersRow GetCurrentRowInDB(NorthwindDataSet.CustomersRow RowWithError)
    {
        this.customersTableAdapter.Fill(tempCustomersDataTable);
    
        NorthwindDataSet.CustomersRow currentRowInDb = 
            tempCustomersDataTable.FindByCustomerID(RowWithError.CustomerID);
    
        return currentRowInDb;
    }
    
    
    //--------------------------------------------------------------------------
    // This method takes a CustomersRow and RowVersion 
    // and returns a string of column values to display to the user.
    //--------------------------------------------------------------------------
    private string GetRowData(NorthwindDataSet.CustomersRow custRow, DataRowVersion RowVersion)
    {
        string rowData = "";
    
        for (int i = 0; i < custRow.ItemArray.Length ; i++ )
        {
            rowData = rowData + custRow[i, RowVersion].ToString() + " ";
        }
        return rowData;
    }
    

Обработка ответа пользователя

При обработке ответа пользователя для окна сообщений требуется код. Можно либо перезаписать текущую запись в базе данных с предложенными изменениями, либо сбросить локальные изменения и обновить таблицу записью, содержащейся в данный момент в базе данных. Если пользователь выбрал значение "Да", метод Merge вызывается с аргументом preserveChanges, равным true. В результате обновление считается успешно завершенным, поскольку исходная версия записи теперь совпадает с версией записи в базе данных.

Чтобы обработать введенные пользователем данные из окна сообщений

  • Добавьте следующий код под кодом, добавленным в предыдущем разделе.

    ' This method takes the DialogResult selected by the user and updates the database 
    ' with the new values or cancels the update and resets the Customers table 
    ' (in the dataset) with the values currently in the database.
    
    Private Sub ProcessDialogResult(ByVal response As Windows.Forms.DialogResult)
    
        Select Case response
    
            Case Windows.Forms.DialogResult.Yes
                NorthwindDataSet.Customers.Merge(TempCustomersDataTable, True)
                UpdateDatabase()
    
            Case Windows.Forms.DialogResult.No
                NorthwindDataSet.Customers.Merge(TempCustomersDataTable)
                MsgBox("Update cancelled")
        End Select
    End Sub
    
    // This method takes the DialogResult selected by the user and updates the database 
    // with the new values or cancels the update and resets the Customers table 
    // (in the dataset) with the values currently in the database.
    
    private void ProcessDialogResult(DialogResult response)
    {
        switch (response)
        {
            case DialogResult.Yes:
                northwindDataSet.Merge(tempCustomersDataTable, true, MissingSchemaAction.Ignore);
                UpdateDatabase();
                break;
    
            case DialogResult.No:
                northwindDataSet.Merge(tempCustomersDataTable);
                MessageBox.Show("Update cancelled");
                break;
        }
    }
    

Проверка

Теперь можно проверить форму, чтобы убедиться, что она работает так, как ожидалось. Для имитации ошибки совместного доступа необходимо изменить данные в базе данных после заполнения NorthwindDataSet.

Чтобы проверить форму, выполните следующие действия:

  1. Нажмите клавишу F5 для запуска приложения.

  2. После отображения формы оставьте ее запущенной и переключитесь на интегрированную среду разработки Visual Studio.

  3. В меню Вид выберите Обозреватель серверов.

  4. В окне Обозреватель серверов разверните узел подключения, используемого приложением, и разверните узел Таблицы.

  5. Щелкните правой кнопкой мыши на таблице Customers и выберите Показать таблицу данных.

  6. В первой записи (ALFKI) измените ContactName на Maria Anders2.

    Примечание

    Перейдите на другую строку для фиксации изменений.

  7. Переключитесь на запущенную форму ConcurrencyWalkthrough.

  8. В первой записи на форме (ALFKI) измените ContactName на Maria Anders1.

  9. Нажмите кнопку Сохранить.

    Возникнет ошибка совместного доступа, и появится окно сообщения.

  10. Нажатие кнопки Нет отменяет обновление и обновляет набор данных значениями, содержащимися в данный момент в базе данных, тогда как нажатие Да записывает предложенное значение в базу данных.

См. также

Основные понятия

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

Привязка элементов управления Windows Forms к данным в Visual Studio

Привязка элементов управления к данным в Visual Studio

Другие ресурсы

Пошаговые руководства работы с данными

Подключение к данным в Visual Studio

Подготовка приложения к получению данных

Выборка данных в приложение

Редактирование данных в приложении

Проверка данных

Сохранение данных