Partilhar via


Manipular uma exceção de simultaneidade em aplicativos de banco de dados .NET Framework

Observação

A DataSet classe e as classes relacionadas são tecnologias herdadas do .NET Framework do início dos anos 2000 que permitem que os aplicativos trabalhem com dados na memória enquanto os aplicativos estão desconectados do banco de dados. As tecnologias são especialmente úteis para aplicativos que permitem aos usuários modificar dados e manter as alterações de volta ao banco de dados. Embora os conjuntos de dados sejam uma tecnologia comprovadamente bem-sucedida, a abordagem recomendada para novos aplicativos .NET é usar o Entity Framework Core. O Entity Framework fornece uma maneira mais natural de trabalhar com dados tabulares como modelos de objeto e tem uma interface de programação mais simples.

As exceções de simultaneidade (System.Data.DBConcurrencyException) são geradas quando dois usuários tentam alterar os mesmos dados em um banco de dados ao mesmo tempo. Neste passo a passo, você cria um aplicativo do Windows que ilustra como capturar um DBConcurrencyException, localizar a linha que causou o erro e aprender uma estratégia para como lidar com ele.

Este passo a passo leva você pelo seguinte processo:

  1. Crie um novo projeto do Aplicativo Windows Forms (.NET Framework ).

  2. Crie um novo conjunto de dados com base na tabela Northwind Customers.

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

  4. Preencha um conjunto de dados com dados da tabela Customers no banco de dados Northwind.

  5. Use o recurso Mostrar Dados da Tabela no Gerenciador de Servidores para acessar os dados da tabela Clientes e alterar um registro.

  6. Altere o mesmo registro para um valor diferente, atualize o conjunto de dados e tente gravar as alterações no banco de dados, o que resulta em um erro de simultaneidade sendo gerado.

  7. Detete o erro e, em seguida, exiba as diferentes versões do registro, permitindo que o usuário determine se deve continuar e atualizar o banco de dados ou cancelar a atualização.

Pré-requisitos

Este passo a passo usa o SQL Server Express LocalDB e o banco de dados de exemplo Northwind.

  1. Se você não tiver o SQL Server Express LocalDB, instale-o na página de download do SQL Server Express ou por meio do Visual Studio Installer. No Visual Studio Installer, você pode instalar o SQL Server Express LocalDB como parte do Armazenamento e processamento de dados carga de trabalho ou como um componente individual.

  2. Instale o banco de dados de exemplo Northwind seguindo estas etapas:

    1. No Visual Studio, abra a janela do Pesquisador de Objetos do SQL Server. (O Pesquisador de Objetos do SQL Server é instalado como parte da carga de trabalho de armazenamento e processamento de dados no Visual Studio Installer.) Expanda o nó SQL Server. Clique com o botão direito do mouse em sua instância LocalDB e selecione New Query.

      Uma janela do editor de consultas é aberta.

    2. Copie o script Northwind Transact-SQL para a área de transferência. Este script T-SQL cria o banco de dados Northwind do zero e o preenche com dados.

    3. Cole o script T-SQL no editor de consultas e depois escolha o botão Executar.

      Após um curto período de tempo, a consulta termina de ser executada e o banco de dados Northwind é criado.

Criar um novo projeto

Comece criando um novo aplicativo do Windows Forms:

  1. No Visual Studio, no menu Ficheiro, selecione Novo>Projeto.

  2. Expanda Visual C# ou Visual Basic no painel esquerdo e, em seguida, selecione Windows Desktop.

  3. No painel central, selecione o tipo de projeto Windows Forms App .

  4. Nomeie o projeto ConcurrencyWalkthrough e escolha OK.

    O projeto ConcurrencyWalkthrough é criado e adicionado ao Gerenciador de Soluções, e um novo formulário é aberto no designer.

Criar o conjunto de dados Northwind

Em seguida, crie um conjunto de dados chamado NorthwindDataSet:

  1. No menu Dados , escolha Adicionar Nova Fonte de Dados.

    Abre-se o Assistente de Configuração da Fonte de Dados.

  2. Na tela Escolha um Tipo de Fonte de Dados , selecione Banco de Dados.

    Assistente de Configuração da Fonte de Dados no Visual Studio

  3. Selecione uma conexão com o banco de dados de exemplo Northwind na lista de conexões disponíveis. Se a conexão não estiver disponível na lista de conexões, selecione Nova conexão.

    Observação

    Se você estiver se conectando a um arquivo de banco de dados local, selecione Não quando perguntado se você gostaria de adicionar o arquivo ao seu projeto.

  4. Na tela Salvar cadeia de conexão no arquivo de configuração do aplicativo , selecione Avançar.

  5. Expanda o nó Tabelas e selecione a tabela Clientes. O nome padrão para o conjunto de dados deve ser NorthwindDataSet.

  6. Selecione Concluir para adicionar o conjunto de dados ao projeto.

Criar um controle DataGridView vinculado a dados

Nesta seção, você cria um System.Windows.Forms.DataGridView arrastando o item Clientes da janela Fontes de Dados para o Windows Form.

  1. Para abrir a janela Fontes de Dados , no menu Dados , escolha Mostrar Fontes de Dados.

  2. Na janela Fontes de Dados, expanda o nó NorthwindDataSet e selecione a tabela Clientes.

  3. Selecione a seta para baixo no nó da tabela e, em seguida, selecione DataGridView na lista suspensa.

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

    Um DataGridView controle chamado CustomersDataGridView e um BindingNavigator chamado CustomersBindingNavigator são adicionados ao formulário vinculado ao BindingSource. Este, por sua vez, está vinculado à tabela Customers no NorthwindDataSet.

Testar o formulário

Agora você pode testar o formulário para garantir que ele se comporte como esperado até este ponto:

  1. Selecione F5 para executar o aplicativo.

    O formulário aparece com um DataGridView controle que é preenchido com dados da tabela Clientes.

  2. No menu Depurar , selecione Parar Depuração.

Manipular erros de simultaneidade

A forma como você lida com os erros depende das regras de negócios específicas que regem seu aplicativo. Para este passo a passo, usamos a estratégia a seguir como um exemplo de como lidar com o erro de simultaneidade.

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

  • O registro atual no banco de dados

  • O registro original que é carregado no conjunto de dados

  • As alterações propostas no conjunto de dados

O usuário pode substituir o banco de dados pela versão proposta ou cancelar a atualização e atualizar o conjunto de dados com os novos valores do banco de dados.

Para habilitar o tratamento de erros de concorrência

  1. Crie um manipulador de erros personalizado.

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

  3. Processar a resposta do usuário.

  4. Reenvie a atualização ou redefina os dados no conjunto de dados.

Adicionar código para manipular a exceção de simultaneidade

Quando você tenta executar uma atualização e uma exceção é gerada, geralmente deseja fazer algo com as informações fornecidas pela exceção gerada. Nesta seção, você adiciona código que tenta atualizar o banco de dados. Você também lida com qualquer DBConcurrencyException que possa ser gerado, assim como com quaisquer outras exceções.

Observação

Os métodos CreateMessage e ProcessDialogResults são adicionados posteriormente no passo a passo.

  1. Adicione o seguinte código abaixo do Form1_Load método:

    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.");
        }
    }
    

  1. Substitua o CustomersBindingNavigatorSaveItem_Click método para chamar o UpdateDatabase método para que ele tenha a seguinte aparência:

    private void customersBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        UpdateDatabase();
    }
    

Opções de exibição para o usuário

O código que você acabou de escrever chama o CreateMessage procedimento para exibir informações de erro para o usuário. Para este passo a passo, você usa uma caixa de mensagem para exibir as diferentes versões do registro para o usuário. Isso permite 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 em um botão) na caixa de mensagem, a resposta é passada para o ProcessDialogResult método.

Crie a mensagem adicionando o seguinte código ao Editor de Códigos. Insira este código abaixo do UpdateDatabase método:

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

Processar a resposta do usuário

Você também precisa de código para processar a resposta do usuário à caixa de mensagem. As opções são substituir 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 que está atualmente no banco de dados. Se o usuário escolher Sim, o Merge método será chamado com o argumento preserveChanges definido como true. Isso faz com que a tentativa de atualização seja bem-sucedida, porque a versão original do registro agora corresponde ao registro no banco de dados.

Adicione o seguinte código abaixo do código que foi 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 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;
    }
}

Testar o comportamento do formulário

Agora você pode testar o formulário para garantir que ele se comporte conforme o esperado. Para simular uma violação de simultaneidade, altere os dados no banco de dados depois de preencher o NorthwindDataSet.

  1. Selecione F5 para executar o aplicativo.

  2. Depois que o formulário for exibido, deixe-o em execução e alterne para o IDE do Visual Studio.

  3. No menu Exibir , escolha Gerenciador de Servidores.

  4. No Explorador de Servidores, expanda a conexão que a sua aplicação está a utilizar e depois expanda o nó Tabelas.

  5. Clique com o botão direito do mouse na tabela Clientes e selecione Mostrar Dados da Tabela.

  6. No primeiro registo (ALFKI), altere ContactName para Maria Anders2.

    Observação

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

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

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

  9. Selecione o botão Salvar .

    O erro de simultaneidade é gerado e a caixa de mensagem é exibida.

    Selecionar Não cancela a atualização e atualiza o conjunto de dados com os valores que estão atualmente no banco de dados. Selecionar Sim grava o valor proposto no banco de dados.