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.
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):
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:
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:
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 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