Na segunda parte deste artigo apresentamos como podemos realizar o tratamento da concorrência com foco no Entity Framework tratando a alteração dos dados.
Vamos continuar mostrando como implementar o tratamento da concorrência onde iremos realizar o tratamento a nível de campos específicos.
Usando o concorrência a nível de campo (Concurrency Mode)
É possível dizer ao Entity Framework para verificar a concorrência para você, e uma maneira de fazer isso é definir a propriedade Concurrency Mode para cada campo que você deseja verificar a concorrência.
A propriedade Concurrency Mode de uma
entidade pode ter dois valores:
|
Este método funciona relativamente bem mesmo se o GBDR (DBMS) não suportar a estratégia da versão do registro (row version) mas apresenta os seguintes efeitos colaterais:
Mesmo assim essa abordagem é válida e você pode usá-la mesmo se o banco de dados não estiver configurado para o tratamento da concorrência a nível de versão de linha(registro).
Tudo o que você precisa fazer é modificar um pouco o modelo.
Vejamos a seguir os procedimentos para realizar esta tarefa.
Vamos continuar usando o nosso exemplo criado no primeiro artigo. Abra o projeto EF_TestandoConcorrencia no VS 2012 Express for desktop.
Abra o Entity Data Model gerado e representando pelo arquivo Concorrencia.edmx e a seguir selecione a propriedade nome da entidade Cliente;
A seguir na janela de propriedades defina o valor para Concorrency Mode como Fixed;
Repita esta operação selecionando os campos DataCompra e Quantidade na entidade Compra e definindo o valor de cada propriedade Concurrency Mode para Fixed (faça uma de cada vez).
Selecione o formulário form1.cs e inclua um novo botão de comando com name = btnVersaoLinha e Text = Concorrência - Versão de Linha conforme mostra a figura abaixo:
Agora clique duas vezes sobre o botão de comando incluído e no evento Click inclua o seguinte código:
private
void btnVersaoLinha_Click(object sender, EventArgs e) { // Cria um contexto para cada usuário ConcorrenciaContainer context1 = new ConcorrenciaContainer(); ConcorrenciaContainer context2 = new ConcorrenciaContainer(); // Pega o registro para o usuario A var UsuarioA = context1.Compras.First(); // Pega o registro para o usuario B var UsuarioB = context2.Compras.First(); // Realiza uma alteração e a salva para o usuario A UsuarioA.Quantidade = Convert.ToDecimal(1.00); context1.SaveChanges(); // Realiza uma alteração e a salva para o usuario A UsuarioB.Quantidade = Convert.ToDecimal(2.00); context2.SaveChanges(); // Exibe a mensagem de sucesso MessageBox.Show("Atualização realizada com sucesso !"); } |
Ao testar este tipo de concorrência esteja certo de que cada usuário possua um contexto diferente para utilizar. Observe que os usuários estão alterando o mesmo campo e que as alterações feitas pelo UsuarioA irão aparecer no banco de dados antes do UsuarioB iniciar a sua alteração. É importante que a alteração tenha sido salva para atualizar a concorrência e dessa forma o UsuarioB irá visualizar um registro diferente.
Vamos ver então como funciona :
Execute o projeto e clique no botão - Testando a Concorrência. Teremos as duas instâncias do formulário AtualizaRegistro conforme mostra a figura a seguir:
1- Selecione o formulário para o Usuario A e altere a quantidade de 1.99 para 4.99. Clique no botão - Concorrência a nível de Campo:
Você verá uma caixa de diálogo contendo o valor atual do banco de dados. Note que o valor da quantidade agora é 4.99 o que confere com o valor atualizado pelo Usuario A.
2- Clique no botão OK para fechar a caixa de mensagem;
3- Clique no botão Cancela das duas janelas de forma a fechar as duas instâncias do formulário AtualizaRegistro.cs e retornar ao formulário Form1.cs;
4- No formulário Form1.cs clique no botão - Concorrência - Versão de Linha;
5- Você verá uma mensagem de erro não tratado exibindo a exceção DbUpdateConcurrencyException conforme a figura abaixo:
Interrompa a execução da aplicação e altere o código do evento Click do botão Concorrência - Versão de Linha do formulário Form1.cs conforme abaixo:
private void btnVersaoLinha_Click(object
sender, EventArgs e) { // Cria um contexto para cada usuário ConcorrenciaContainer context1 = new ConcorrenciaContainer(); ConcorrenciaContainer context2 = new ConcorrenciaContainer(); // Pega o registro para o usuario A var UsuarioA = context1.Compras.First(); // Pega o registro para o usuario B var UsuarioB = context2.Compras.First();
// Realiza uma alteração e a salva para o usuario A
try
// Salva as alterações
// Exibe a mensagem de sucesso |
Você deve acrescentar também os seguintes namespaces no formulário Form1.cs:
using
System.Data.Entity.Infrastructure;Na versão 6.0 do Entity Framework (esta é a versão que estou usando) afim de atualizar o registro você tem que atualizar o contexto do objeto.
A exceção DbUpdateConcurrencyException disponibiliza a você a entidade que falhou durante a atualização e quando você chama o método Refresh você tem que fornecer uma estratégia para atualizar o banco de dados.
O passo final é chamar o método SaveChanges() e neste ponto a atualização será bem sucedida com uma abordagem client-wins.
Em um sistema projetado
para alertá-lo dos conflitos, o sistema irá alertar quando o usuário for
tentar salvar seus dados, indicando que o registro foi modificado desde o
tempo em que foi inicialmente recuperado.
Essa abordagem é conhecida como ClientWins e não ignora a concorrência; neste cenário o EF emite um comando para atualizar TODOS os valores da entidade, mesmo aqueles que não tenham sido editados. O impacto desta abordagem no cenário descrito do item anterior é que o campo X e todos os outros campos no registro do banco de dados serão alterados para refletir a versão do usuário dos dados. |
Pressione F5 para executar a aplicação novamente;
Testando a Concorrência. Teremos as duas instâncias do formulário AtualizaRegistro conforme mostra a figura a seguir:
1- Selecione o formulário para o Usuario A e altere a quantidade de 1.99 para 4.99. Clique no botão - Concorrência a nível de Campo:
Você verá uma caixa de diálogo contendo o valor atual do banco de dados. Note que o valor da quantidade agora é 4.99 o que confere com o valor atualizado pelo Usuario A.
2- Clique no botão OK para fechar a caixa de mensagem;
3- Clique no botão Cancela das duas janelas de forma a fechar as duas instâncias do formulário AtualizaRegistro.cs e retornar ao formulário Form1.cs;
4- No formulário Form1.cs clique no botão - Concorrência - Versão de Linha;
5- Você verá uma caixa de mensagem informando que a tentativa inicial de atualização falhou;
Clicando no botão OK você verá uma
nova caixa de mensagem informando que a atualização foi realizada com sucesso
!
Isso foi possível graças ao tratamento da exceção que fizemos usando a estratégia de concorrência a nível de campo usando a propriedade Concurrency Mode igual a Fixed.
Na continuação deste artigo irei abordar a concorrência a nível de registro usando rowversion.
Joã 3:26
Joã 3:27
Respondeu João: O homem não pode receber coisa alguma, se não lhe for dada do céu.Joã 3:28
Vós mesmos me sois testemunhas de que eu disse: Não sou o Cristo, mas sou enviado adiante dele.Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
VB 2005 - Introdução a concorrência de dados - Macoratti.net
ADO .NET - Verificando a violação de concorrência - Macoratti.net
Arquitetura de dados desconectada e a concorrência - Macoratti.net