Manipular uma exceção de simultaneidade em aplicativos de banco de dados do .NET Framework
Observação
Os conjuntos de dados 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 bastante úteis em aplicativos que permitem que os usuários modifiquem dados e persistam as alterações no banco de dados. Embora os conjuntos de dados tenham se mostrado uma tecnologia muito bem-sucedida, é recomendado que os novos aplicativos .NET usem o Entity Framework Core. O Entity Framework proporciona uma forma mais natural de trabalhar com dados tabulares como modelos de objeto e conta com uma interface de programação mais simples.
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 uma DBConcurrencyException, localizar a linha que causou o erro e aprender uma estratégia de como lidar com isso.
Este guia orienta você no seguinte processo:
Crie um novo projeto Windows Forms App (.NET Framework).
Criar um conjunto de dados com base na tabela Northwind Customers.
Criar um formulário com um DataGridView para exibir os dados.
Preencher um conjunto de dados com dados da tabela Clientes no banco de dados da Northwind.
Usar o recurso Mostrar Dados da Tabela no Gerenciador de Servidores para acessar os dados da tabela Clientes e alterar um registro.
Alterar o mesmo registro para um valor diferente, atualizar o conjunto de dados e tentar gravar as alterações no banco de dados, o que resultará na geração de um erro de simultaneidade.
Capturar o erro e exibir as diferentes versões do registro, permitindo que o usuário determine se deseja 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 da Northwind.
Se você não tiver SQL Server Express LocalDB, instale-o por meio da página de download do SQL Server Express ou usando o Instalador do Visual Studio. No Instalador do Visual Studio, você pode instalar o SQL Server Express LocalDB como parte da carga de trabalho Armazenamento e processamento de dados ou como um componente individual.
Instale o banco de dados de exemplo da Northwind seguindo estas etapas:
No Visual Studio, abra a janela Pesquisador de Objetos do SQL Server. (O Pesquisador de Objetos do SQL Server é instalado como parte da carga de trabalho Armazenamento e processamento de dados no Instalador do Visual Studio). Expanda o nó do SQL Server. Clique com o botão direito do mouse na instância do LocalDB e selecione Nova Consulta.
Uma janela do editor de consultas vai se abrir.
Copie o script Transact-SQL da Northwind para sua área de transferência. Esse script T-SQL cria o banco de dados da Northwind do zero e o preenche com alguns dados.
Cole o script T-SQL no editor de consultas e, em seguida, escolha o botão Executar.
Após um curto período, a consulta termina de ser executada e o banco de dados da Northwind é criado.
Criar um novo projeto
Comece criando um aplicativo do Windows Forms:
No Visual Studio, no menu Arquivo, selecione Novo>Projeto.
Expanda Visual C# ou Visual Basic no painel esquerdo e selecione Área de Trabalho do Windows.
No painel central, selecione o tipo de projeto Aplicativo do Windows Forms.
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 da Northwind
Em seguida, crie um conjunto de dados chamado NorthwindDataSet:
No menu Dados, clique em Adicionar Nova Fonte de Dados.
O Assistente de Configuração de Fonte de Dados é aberto.
Na tela Escolher um Tipo de Fonte de Dados, selecione Banco de Dados.
Selecione uma conexão com o banco de dados de exemplo da 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 for perguntado se deseja adicionar o arquivo ao seu projeto.
Na tela Salvar cadeia de conexão no arquivo de configuração de aplicativo, selecione Avançar.
Expanda o nó Tabelas e selecione a tabela Clientes. O nome padrão do conjunto de dados deve ser NorthwindDataSet.
Selecione Concluir para adicionar o conjunto de dados ao projeto.
Criar um controle DataGridView associado a dados
Nesta seção, você criará um System.Windows.Forms.DataGridView arrastando o item Clientes da janela Fontes de Dados para o Formulário do Windows.
Para abrir a janela Fontes de Dados, no menu Dados, escolha Mostrar Fontes de Dados.
Na janela Fontes de Dados, expanda o nó NorthwindDataSet e selecione a tabela Clientes.
Selecione a seta para baixo no nó da tabela e, em seguida, selecione DataGridView na lista suspensa.
Arraste a tabela para uma área vazia do formulário.
Um controle DataGridView chamado CustomersDataGridView e um BindingNavigator chamado CustomersBindingNavigator é adicionado ao formulário associado ao BindingSource. Este, por sua vez, está associado à tabela Clientes no NorthwindDataSet.
Testar o formulário
Agora você pode testar o formulário para verificar se ele se comporta da forma esperada até o momento:
Selecione F5 para executar o aplicativo.
O formulário é exibido com um controle DataGridView que é preenchido com os dados da tabela Clientes.
No menu Depurar, selecione Interromper Depuração.
Tratar erros de simultaneidade
A maneira como você trata os erros depende das regras de negócios específicas que regem seu aplicativo. Neste passo a passo, usamos a estratégia a seguir como exemplo para 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 carregado no conjunto de dados
As alterações propostas no conjunto de dados
Em seguida, 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 simultaneidade
Crie um manipulador de erros personalizado.
Mostre opções para o usuário.
Processe a resposta do usuário.
Reenvie a atualização ou redefina os dados no conjunto de dados.
Adicionar código para tratar a exceção de simultaneidade
Quando você tenta executar uma atualização e uma exceção é gerada, geralmente você faz 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. Você também vai tratar qualquer DBConcurrencyException que possa ser gerada, bem como quaisquer outras exceções.
Observação
Os métodos CreateMessage
e ProcessDialogResults
são adicionados posteriormente no passo a passo.
Adicione o seguinte código ao método
Form1_Load
: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."); } }
Substitua o método
CustomersBindingNavigatorSaveItem_Click
para chamar o métodoUpdateDatabase
para que ele fique com a seguinte aparência:
Mostrar 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. Neste passo a passo, você vai usar uma caixa de mensagem para exibir as diferentes versões do registro para o usuário. Isso permitirá que o usuário escolha se deseja substituir o registro pelas alterações ou cancelar a edição. Depois que o usuário seleciona uma opção (clica em um botão) na caixa de mensagem, a resposta é passada para o método ProcessDialogResult
.
Crie a mensagem adicionando o código a seguir ao Editor de Códigos. Insira este código abaixo do método UpdateDatabase
:
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 pela 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 método Merge será chamado com o argumento preserveChanges definido como true. Isso fará com que a tentativa de atualização seja bem-sucedida, pois a versão original do registro agora corresponde ao registro que está 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, é possível testar o formulário para garantir que ele se comporta da forma esperada. Para simular uma violação de simultaneidade, altere os dados no banco de dados depois de preencher o NorthwindDataSet.
Selecione F5 para executar o aplicativo.
Depois que o formulário for exibido, deixe-o em execução e alterne para o IDE do Visual Studio.
No menu Exibir, escolha Gerenciador de Servidores.
No Gerenciador de Servidores, expanda a conexão que seu aplicativo está usando e expanda o nó Tabelas.
Clique com o botão direito do mouse na tabela Clientes e selecione Mostrar Dados da Tabela.
No primeiro registro (ALFKI), altere ContactName para Maria Anders2.
Observação
Navegue até uma linha diferente para confirmar a alteração.
Alterne para o formulário em execução do ConcurrencyWalkthrough.
No primeiro registro no formulário (ALFKI), altere ContactName para Maria Anders1.
Selecione o botão Salvar.
O erro de simultaneidade é gerado e a caixa de mensagem é exibida.
A seleção de Não cancelará a atualização e atualizará o conjunto de dados com os valores que estão atualmente no banco de dados. A seleção de Sim gravará o valor proposto no banco de dados.