Tratamento de falhas nas confirmações de transações
Observação
Somente o EF6.1 em diante: os recursos, APIs, etc. discutidos nesta página foram apresentados no Entity Framework 6.1. Se você estiver usando uma versão anterior, algumas ou todas as informações não se aplicarão.
Como parte da versão 6.1, estamos introduzindo um novo recurso de resiliência de conexão para o EF: a capacidade de detectar e recuperar automaticamente quando falhas transitórias de conexão afetam a confirmação de confirmações de transações. Os detalhes completos do cenário são melhor descritos na postagem do blog Conectividade do Banco de Dados SQL e o problema da idempotência. Em resumo, o cenário é que, quando uma exceção é levantada durante uma confirmação de transação, existem duas causas possíveis:
- A confirmação da transação falhou no servidor
- A confirmação da transação foi bem-sucedida no servidor, mas um problema de conectividade impediu que a notificação de êxito chegasse ao cliente.
Quando ocorre a primeira situação, o aplicativo ou o usuário pode repete a operação, mas quando ocorre a segunda situação, as tentativas devem ser evitadas e o aplicativo pode se recuperar automaticamente. O desafio é que, sem a capacidade de detectar qual foi o motivo real pelo qual uma exceção foi relatada durante a confirmação, o aplicativo não pode escolher o curso de ação correto. O novo recurso do EF 6.1 permite que o EF verifique novamente com o banco de dados se a transação foi bem-sucedida e tome a atitude correta de forma transparente.
Usar o recurso
Para habilitar o recurso, você precisa incluir uma chamada para SetTransactionHandler no construtor da sua DbConfiguration. Se você não estiver familiarizado com DbConfiguration, consulte Configuração Baseada em Código. Esse recurso pode ser utilizado em combinação com as novas tentativas automáticas que apresentamos no EF6, que ajudam na situação em que a transação realmente falhou ao confirmar no servidor devido a uma falha transitória:
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.SqlServer;
public class MyConfiguration : DbConfiguration
{
public MyConfiguration()
{
SetTransactionHandler(SqlProviderServices.ProviderInvariantName, () => new CommitFailureHandler());
SetExecutionStrategy(SqlProviderServices.ProviderInvariantName, () => new SqlAzureExecutionStrategy());
}
}
Como as transações são rastreadas
Quando o recurso estiver habilitado, o EF adicionará automaticamente uma nova tabela ao banco de dados chamada __Transactions. Uma nova linha é inserida nessa tabela sempre que uma transação é criada pelo EF e a existência dessa linha é verificada se ocorrer uma falha na transação durante a confirmação.
Embora o EF se esforce ao máximo para remover as linhas da tabela quando elas não forem mais necessárias, a tabela pode crescer se o aplicativo for encerrado prematuramente e, por esse motivo, você precisará limpar a tabela manualmente em alguns casos.
Como fazer para lidar com confirmações de falhas em versões anteriores
Antes do EF 6.1, não existia nenhum mecanismo para lidar com confirmações de falhas no produto EF. Existem várias maneiras de lidar com essa situação que podem ser aplicadas às versões anteriores do EF6:
Opção 1: não fazer nada
A probabilidade de uma falha de conexão durante a confirmação da transação é baixa, portanto, pode ser aceitável que seu aplicativo simplesmente falhe se essa condição realmente ocorrer.
Opção 2: usar o banco de dados para redefinir o estado
- Descartar o DbContext atual
- Criar um novo DbContext e restaurar o estado do seu aplicativo a partir do banco de dados
- Informe ao usuário que a última operação pode não ter sido concluída com êxito.
Opção 3: rastrear a transação manualmente
- Adicione uma tabela não rastreada ao banco de dados utilizada para rastrear o status das transações.
- Insira uma linha na tabela no início de cada transação.
- Se a conexão falhar durante as confirmações, verifique a presença da linha correspondente no banco de dados.
- Se a linha estiver presente, continue normalmente, pois a transação foi confirmada com êxito
- Se a linha estiver ausente, utilize uma estratégia de execução para repetir a operação atual.
- Se as confirmações forem bem-sucedidas, exclua a linha correspondente para evitar o crescimento da tabela.
Esta postagem do blog contém código de exemplo para realizar isso no Banco de Dados SQL do Azure.