Entity Framework - Tratando o problema da concorrência de dados a nível de registro - IV


Na terceira parte deste artigo apresentamos como podemos realizar o  tratamento da concorrência com foco no Entity Framework tratando a concorrência a nível de campo.

Vamos continuar mostrando como implementar o tratamento da concorrência onde iremos realizar o tratamento a nível de registro.

Usando o concorrência a nível de registro (row-version)

Se você esta usando o SQL Server como banco de dados saiba que ele fornece um tipo especial de dado chamado rowversion o qual permite que você gerencia o número da versão dos dados para cada registro.

Comparando o número gerado pelo rowversion com o número obtido quando o dado é lido é possível determinar se ocorreu um problema de concorrência.

Tudo o que você tem que fazer é definir em cada tabela do seu modelo uma coluna do tipo rowversion e depois realizar o tratamento que iremos mostrar neste artigo.

É um tipo de dados que expõe números binários exclusivos, gerados automaticamente, em um banco de dados. O rowversion geralmente é usado como um mecanismo para linhas de tabela de carimbo de versão. O tamanho de armazenamento é de 8 bytes. O tipo de dados rowversion é apenas um número que aumenta e não preserva uma data nem hora. Para gravar uma data ou hora, use um tipo de dados datetime2.

Cada banco de dados tem um contador que é incrementado para cada operação de inserção ou atualização executada em uma tabela que contém uma coluna rowversion no banco de dados. Esse contador é a rowversion do banco de dados. Isso controla uma hora relativa em um banco de dados, não uma hora real que pode ser associada a um relógio.

Uma tabela só pode ter uma coluna rowversion. Sempre que uma linha com uma coluna rowversion é modificada ou inserida, o valor rowversion do banco de dados incrementado é inserido na coluna rowversion. Essa propriedade torna uma coluna rowversion uma candidata pobre a chaves, principalmente chaves primárias. Qualquer atualização feita na linha altera o valor de rowversion e, portanto, altera o valor de chave.

Você pode usar a coluna rowversion de uma linha para determinar facilmente se algum valor na linha foi alterado desde a última vez que foi lido. Se qualquer alteração for feita na linha, o valor de rowversion será atualizado. Se nenhuma alteração for feita na linha, o valor de rowversion será o mesmo que foi lido anteriormente. Para retornar o valor de rowversion atual para um banco de dados, use @@DBTS.

fonte: http://technet.microsoft.com/pt-br/library/ms182776.aspx

Vejamos a seguir os procedimentos para realizar este recurso.

Vamos continuar usando o nosso exemplo criado no primeiro artigo. Abra o projeto EF_TestandoConcorrencia no VS 2012 Express for desktop.

Agora abra o DataBase Explorer no Visual Studio e localize o banco de dados Macoratti.mdf que estamos usando nos exemplos deste artigo. Lembre-se que no primeiro artigo criamos o modelo de entidades usando o Model First e a seguir criamos o banco de dados Macoratti.mdf.

Expanda os objetos do banco de dados Macoratti.mdf na janela DataBase Explorer (ou Server Explorer se você estiver usando o Visual Studio 2012)

Clique com o botão direito sobre a tabela Clientes e a seguir clique em Open Table Definition;

Na janela Open Table Definition inclua uma coluna com o nome RowVersion e escolha o Data Type rowversion desmarcando a caixa de verificação Allow Nulls;

A seguir clique em Update e na próxima janela confirme clicando em Update DataBase de forma que a alteração se reflita no banco de dados conforme mostra a figura a seguir:

Repita este procedimento para a tabela Compras incluindo uma coluna RowVersion do tipo rowversion e atualizando o banco de dados. Ao final você deverá ver na janela DataBase Explorer (após clicar em Refresh) o seguinte resultado:

Agora na janela Solution Explorer clique duas veze sobre o arquivo Concorrencia.edmx para visualizar o modelo de entidades gerado e a seguir clique com o botão direito do mouse sobre a área vazia do descritor;

Será aberto um menu suspenso e você deve clicar em Update Model from DataBase para atualizar o modelo de entidades com as alterações feitas nas tabelas;

Na próxima janela clique em Finish e em seguida você verá o modelo de entidades atualizado conforme figura  abaixo:

Agora, no modelo de entidades, selecione a propriedade nome e na janela de propriedades retorne o valor de Concurrency Mode de Fixed para None; (Fizemos esta alteração no artigo anterior)

Após isso selecione a propriedade RowVersion e na janela de propriedades altere a propriedade Concurrency Mode de None para Fixed;

Na entidade Compra selecione as propriedades DataCompra e Quantidade e retorne o valor de Concurrency Mode de Fixed para None;

Após isso selecione a propriedade RowVersion e na janela de propriedades altere a propriedade Concurrency Mode de None para Fixed;

Dessa forma teremos a nova propriedade RowVersion com sua propriedade Concurrency Mode definida para Fixed em ambas as entidades.

Agora podemos executa o projeto pressionando F5 e visualizar o formulário Form1 sendo exibido:

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 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 !
 

 

Percebeu que não fizemos alteração alguma no código pois já tínhamos tratado a concorrência tratando a exceção DbUpdateConcurrencyException que também foi lançada para este exemplo.

 

Na continuação irei abordar outros aspectos envolvidos na concorrência com Entity Framework como a concorrência pessimista.


Pegue o projeto completo aqui: EF_TestandoConcorrencia.zip

Joã 3:26 E foram ter com João e disseram-lhe: Rabi, aquele que estava contigo além do Jordão, do qual tens dado testemunho, eis que está batizando, e todos vão ter com ele.

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:


José Carlos Macoratti