Compartilhar via


Passo a passo: Manipulando uma exceção de simultaneidade

Exceções de simultaneidade (DBConcurrencyException) são geradas quando dois usuários tentam alterar os mesmos dados em um banco de dados ao mesmo tempo.Nesta explicação passo a passo você cria um aplicativo do Windows que ilustra a captura de DBConcurrencyException, localizando a linha que causou o erro, e uma estratégia para você poder usar no tratamento dele.

Esta explicação passo a passo leva você através do seguinte processo:

  1. Criar um novo projeto Windows Application.

  2. Crie um novo dataset baseado na tabela Customers do Northwind.

  3. Crie um formulário com um DataGridView para exibir os dados.

  4. Preencher um dataset com dados da tabela Customers do banco de dados Northwind.

  5. Após preencher o conjunto de dados, use o Visual Database Tools no Visual Studio para acessar diretamente a tabela de dados Customers e alterar um registro.

  6. Então no formulário, altere o mesmo registro com um valor diferente, atualize o dataset, e tente gravar as alterações no banco de dados, que resulta na geração de um erro concorrente.

  7. Capture o erro, e exiba as diferentes versões do registro, permitindo ao usuário determinar se deseja continuar e atualizar o banco de dados, ou cancelar a atualização.

Pré-requisitos

Para concluir esta explicação passo a passo, você precisa:

ObservaçãoObservação

As caixas de diálogo e comandos de menu demonstradas podem ser diferentes daqueles descritos na Ajuda, dependendo das configurações ativas ou configurações de edição.Para alterar as configurações, escolha Import and Export Settings sobre o Ferramentas menu.Para obter mais informações, consulte Configurações de Visual Studio.

Criando um novo projeto

Você começará com a explicação passo a passo de como criar um novo aplicativo do Windows.

Para criar um novo projeto de Aplicativo do Windows

  1. No menu File, crie um novo projeto.

  2. Selecione uma linguagem de programação no painel Project Types.

  3. Selecione Windows Application no painel Templates.

  4. Nomeie o projeto como ConcurrencyWalkthrough, e clique OK.

    O Visual Studio adiciona o projeto ao Solution Explorer e exibe um novo formulário no designer.

Criando o dataset Northwind

Nesta seção você criará um conjunto de dados chamado NorthwindDataSet.

Para criar o NorthwindDataSet

  1. No menu Data, escolha Add New Data source.

    The Data Source Configuration Wizard opens.

  2. Selecione Database na página Choose a Data Source Type.

  3. Selecione uma conexão para o banco de dados de exemplo Northwind a partir da lista de conexões disponíveis, ou clique em New Connection Se a conexão não estiver disponível na lista de conexões.

    ObservaçãoObservação

    Se você estiver se conectando a um arquivo de banco de dados local, selecione No quando perguntado se você deseja adicionar o arquivo no seu projeto.

  4. Clique Next na página Save connection string to the application configuration file.

  5. Expanda o nó Tables e selecione a tabela Customers.O nome padrão para o dataset deve ser NorthwindDataSet.

  6. Clique Finish para adicionar o dataset para o projeto.

Criar um controle acoplado Data-DataGridView

Nesta seção você criará um DataGridView arrastando o item Customers da janela Data Sources para seu Formulário do Windows.

Para criar um controle DataGridView que está acoplado à tabela Clientes

  1. No menu Data, escolha Show Data Sources para abrir o Data Sources Window.

  2. Expanda o nó NorthwindDataSet a partir da janela Data Sources e selecione a tabela Customers.

  3. Clique na seta para baixo no nó da tabela e selecione DataGridView na lista suspensa.

  4. Arraste a tabela para uma área vazia do seu formulário.

    Um controle DataGridView nomeado CustomersDataGridView e um BindingNavigator nomeado CustomersBindingNavigator são adicionados ao formulário ligado ao BindingSource que é por sua vez ligado à tabela Customers no NorthwindDataSet.

Ponto de Verificação

Agora você pode testar o formulário para certificar-se que ele funciona como esperado até este ponto.

Para testar o formulário

  1. Pressione F5 para executar o aplicativo

    O formulário é exibido com um controle DataGridView nele que é preenchido com dados da tabela Customers.

  2. A partir do Menu Debug, escolha Stop Debugging.

Manipular erros concorrentes

Como você manipula os erros depende como as regras específicas do negócio governam o aplicativo.Para esta explicação passo a passo, após a geração de uma violação de concorrência, a estratégia de manipulação do erro concorrência a seguir será usada como uma ilustração:

O aplicativo apresentará ao usuário três versões do registro:

  • O registro atual no banco de dados.

  • O registro original carregado para o dataset.

  • As alterações propostas no dataset.

O usuário é então capaz de substituir o banco de dados com a versão proposta ou cancelar a atualização e atualizar o dataset com os novos valores do banco de dados.

Para ativar o tratamento de erros concorrência

  1. Criar um manipulador de erro personalizado.

  2. Exibir as opções para o usuário.

  3. Processar a resposta do usuário.

  4. Reenviar a atualização, ou redefinir os dados no dataset.

ms171936.collapse_all(pt-br,VS.110).gifAdicionar o código para tratar a exceção concorrente

Quando você tentar executar uma atualização e uma exceção é gerada, você geralmente deseja fazer algo com as informações fornecidas pela exceção gerada.

Nesta seção você adicionará um código que tentará atualizar o banco de dados e manipular qualquer DBConcurrencyException que pode ser gerada, bem como qualquer outra exceção.

ObservaçãoObservação

O CreateMessage e os métodos ProcessDialogResults serão adicionados posteriormente nessa explicação passo a passo.

Para adicionar o tratamento de erro para o erro de concorrência

  1. Adicione o seguinte código abaixo do método 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. Substitua o método CustomersBindingNavigatorSaveItem_Click para chamar o método UpdateDatabase para que ele seja semelhante ao seguinte:

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

ms171936.collapse_all(pt-br,VS.110).gifExibir as opções para o usuário

O código que você acabou de escrever chama o procedimento CreateMessage para exibir informações de erro para o usuário.Para esta explicação passo a passo, você usará uma caixa de mensagem para exibir as diferentes versões do Registro para o usuário e permitir que o usuário escolha se deseja substituir o registro com as alterações ou cancelar a edição.Uma vez que o usuário seleciona uma opção (clica num botão) na caixa de mensagem, a resposta é passada para o método ProcessDialogResult.

Para criar a mensagem a ser exibida para o usuário

  • Crie a mensagem, adicionando o seguinte código para o Code Editor.Digite este código abaixo do método 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;
    }
    

ms171936.collapse_all(pt-br,VS.110).gifProcessando resposta do usuário

Você também precisará codificar para processar a resposta do usuário à caixa de mensagem.As opções são tanto sobrescrever o registro atual no banco de dados com a alteração proposta ou abandonar as alterações locais e atualizar a tabela de dados com o registro corrente no banco de dados.Se o usuário escolher sim, o método Merge é chamado com o argumento preserveChanges definido como true.Isso fará com que a tentativa de atualização ser bem sucedida, porque agora a versão original do registro coincide com o registro no banco de dados.

Para processar a entrada de usuário na caixa de mensagem

  • Adicione o seguinte código abaixo ao código adicionado na seção anterior.

    ' 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;
        }
    }
    

Testando

Agora você pode testar o formulário para certificar-se de que ele funciona comforme o esperado.Para simular uma violação de concorrência você precisa alterar os dados no banco de dados após preenchê no NorthwindDataSet.

Para testar o formulário

  1. Pressione F5 para executar o aplicativo.

  2. Após o formulário aparecer, deixe-lo funcionando e alterne para a IDE do Visual Studio.

  3. No menu View, escolha Server Explorer.

  4. No Server Explorer, expanda a conexão que seu aplicativo está usando e expanda o nó Tables.

  5. Clique com o botão direito do mouse na tabela Customers e selecione Show Table Data.

  6. No primeiro registro (ALFKI) altere o ContactName para .

    ObservaçãoObservação

    Navegue até uma linha diferente para confirmar a alteração.

  7. Alterne para ConcurrencyWalkthrough do formulário em execução.

  8. No primeiro registro no formulário (ALFKI), alterar o ContactName para Maria Anders1.

  9. Clique no botão Save.

    O erro de concorrência é gerado, e a caixa de mensagem aparece.

  10. Clicar em No cancela a atualização e atualiza o dataset com os valores correntes no banco de dados, enquanto clicar em Yes grava o valor proposto para o banco de dados.

Consulte também

Conceitos

Novidades para desenvolvimento de aplicativos de dados no Visual Studio 2012

Vinculando controles do Windows Forms a dados em Visual Studio

Preparando seu aplicativo para receber dados

Buscando dados em seu aplicativo.

Controles de vinculação de dados de Visual Studio

Edição de dados em seu aplicativo.

Validação de dados

Salvar dados

Outros recursos

Explicações passo a passo de dados

Connecting to Data in Visual Studio