Back-End

9 jul, 2014

Entity Framework – Tratando o problema da concorrência de dados a nível de registro – Parte 04

Publicidade

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. Hoje 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ê está usando o SQL Server como banco de dados, saiba que ele fornece um tipo especial de dado chamado rowversion, que permite que você gerencie 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, então 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):

ef_tpc41

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;

ef_tpc42

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:

ef_tpc43

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:

ef_tpc44

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;

ef_tpc45

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

ef_tpc46

No modelo de entidades, selecione a propriedade nome e na janela de propriedades retorne o valor de Concurrency Mode de Fixed para None; Lembre-se que 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:

ef_tpc33 (1)

Clique no botão – Testando a Concorrência. Teremos as duas instâncias do formulário AtualizaRegistro conforme mostra a figura a seguir:

ef_tpc34 (2)

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.

ef_tpc35 (2)

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;

ef_tpc34 (3)

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;

ef_tpc37 (1)

Clicando no botão OK, você verá uma nova caixa de mensagem informando que a atualização foi realizada com sucesso.

ef_tpc38 (1)

Percebeu que não fizemos alteração alguma no código, pois já tínhamos tratado a concorrência ao tratar 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