Introdução
O LINQ-to-SQL oferece uma coleção de APIs (Application Program Interface) para auxiliar o desenvolvedor a identificar, avaliar e solucionar conflitos de concorrência nas suas aplicações.
Concorrência Otimista
O modelo otimista para gerenciamento de conflitos de concorrência utiliza o método Resolve(RefreshMode) apresentado pelo Namespace System.Data.Linq. Este método avalia o conflito e atualiza os dados de acordo com o que foi definido pelo desenvolvedor através da Enumeração RefreshMode.
Enumeração RefreshMode
Esta enumeração determina como o método Resolve() irá tratar os conflitos de concorrência expostos pela Exception ChangeConflictException. Abaixo estão os membros desta enumeração com uma breve descrição:
Membro
|
Descrição
|
KeepCurrentValues
|
Força o método Resolve a substituir os valores originais com os valores contidos no banco de dados. Nenhum valor atual é modificado.
|
KeepChanges
|
Força o método Resolve a manter os valores atuais que foram modificados, mas atualiza outros valores com os valores contidos no banco de dados.
|
OverwriteCurrentValues
|
Força o método Resolve a sobrescrever os valores atuais com os valores contidos no banco de dados. |
Entendendo o RefreshMode
Analisando a Enumeração acima, o desenvolvedor pode ter uma interpretação equivocada sobre o comportamento do método Resolve(). Para esclarecer isso abaixo estão três cenários diferentes que ilustram o comportamento do método Resolve para cada Membro da Enumeração RefreshMode.
Cenário de Exemplo
Considere o cenário abaixo. Uma Exception do tipo ChangeConflictException é gerada quando o Usuário1 tenta submeter suas alterações ao banco de dados, porque o Usuário2 efetivou modificações nos dados enquanto o Usuário1 estava manipulando o mesmo registro.
Ação/Situação
|
Colunas da Tabela Funcionario
|
Manager
|
Assistant
|
Department
|
Valores originais quando os usuários 1 e 2 obtiveram os dados
|
Alfreds
|
Maria
|
Sales
|
O Usuário1 tenta submeter as seguintes alterações
|
Alfred
|
(não modificado)
|
Marketing
|
O Usuário2 já tinha efetivado as seguintes alterações
|
(não modificado)
|
Mary
|
Service |
Resolvendo conflitos mesclando dados (KeepChanges)
O membro KeepChanges pode ser utilizado para reconciliar diferenças entre os valores esperados e os valores reais contidos no banco de dados antes de você tentar submeter a atualização novamente. Este membro mescla dados do cliente com dados contidos na base.
Ação/Situação
|
Colunas da Tabela Funcionario
|
Manager
|
Assistant
|
Department
|
Estado dos dados após a solução do conflito
|
Alfred
(Usuário 1)
|
Mary
(Usuário 2)
|
Marketing
(Usuário 1) |
Resolvendo conflitos mantendo os dados do banco (OverwriteCurrentValues)
O membro OverwriteCurrentValues pode ser utilizado para reconciliar diferenças entre os valores esperados e os valores reais contidos no banco de dados antes de você tentar submeter a atualização novamente. Este membro sobrescreve os valores atuais (no cliente) com os valores encontrados no banco de dados.
Ação/Situação
|
Colunas da Tabela Funcionario
|
Manager
|
Assistant
|
Department
|
Estado dos dados após a solução do conflito
|
Alfreds
(Original)
|
Mary
(Usuário 2)
|
Service
(Usuário 2) |
Resolvendo conflitos sobrescrevendo os valores do banco de dados (KeepCurrentValues)
O membro KeepCurrentValues pode ser utilizado para reconciliar diferenças entre os valores esperados e os valores reais contidos no banco de dados antes de você tentar submeter a atualização novamente. Este membro sobrescreve os valores do banco de dados com os valores atuais no cliente.
Ação/Situação
|
Colunas da Tabela Funcionario
|
Manager
|
Assistant
|
Department
|
Estado dos dados após a solução do conflito
|
Alfred
(Usuário 1)
|
Maria
(Original)
|
Marketing
(Usuário 1) |
Exemplo de implementação do modelo de concorrência otimista
O procedimento abaixo apresenta o código necessário para implementação do modelo otimista. A linha em destaque mostra a chamada do método Resolve() onde o desenvolvedor pode escolher a ação desejada de acordo com a enumeração RefreshMode.
try
{
db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
Console.WriteLine(e.Message);
foreach (ObjectChangeConflict occ in db.ChangeConflicts)
{
occ.Resolve(RefreshMode.KeepCurrentValues);
}
}