Visão geral
Neste guia, você pode aprender como usar transações em seus aplicativos do EF Core Provider. Uma transação envolve uma série de operações de escrita. Se qualquer operação na transação falhar, o fornecedor reverterá todas as alterações na transação. Esse comportamento ajuda a garantir a consistência dos dados.
O fornecedor do EF Core oferece suporte aos seguintes modos de transação:
Transações implícitas: o provedor envolve automaticamente as chamadas para os
SaveChanges()SaveChangesAsync()métodos e em uma transação.Consulte Configurar transações implícitas para saber como configurar ou desabilitar esse comportamento.Transações explícitas: você chama o
Database.BeginTransaction()método para iniciar manualmente uma transação e, em seguida, confirmar ou reverter a transação chamandoCommit()Rollback()ou.
Dados de amostra
Os exemplos neste guia usam a coleção planets do banco de dados sample_guides . Os documentos nesta coleção utilizam a seguinte classe Planet como um modelo:
public class Planet { public ObjectId _id { get; set; } public string name { get; set; } = null!; public int orderFromSun { get; set; } public bool hasRings { get; set; } }
Essa collection é dos conjuntos de dados de amostra fornecidos pelo Atlas.Consulte o guia Início Rápido para aprender como criar um cluster MongoDB gratuito e carregar estes dados de amostra.
Requisitos e limitações
Antes de usar transações, observe os seguintes requisitos e limitações:
As transações exigem um sistema do MongoDB Server que ofereça suporte a transações de vários documentos, como um conjunto de réplicas ou cluster fragmentado. Se o seu aplicação tentar iniciar uma transação em um sistema autônomo , o fornecedor lançará
NotSupportedExceptionum. Para evitar isso,AutoTransactionBehavior.Neverdefina conforme descrito em Configurar transações implícitas.O EF Core Provider não suporta transações de ambiente .NET , como aquelas criadas por
System.Transactions.TransactionScope. Se você tentar usar uma transação ambiente, o fornecedor lançará uma exceção. Em vez disso, use transações implícitas ou explícitas.
Transações implícitas
Por padrão, o provedor de núcleo da EF envolve automaticamente SaveChanges() as SaveChangesAsync() chamadas e em uma transação quando várias entidades raiz são afetadas. Uma entidade raiz é um documento de nível superior em uma coleção, em oposição a um tipo próprio ou incorporado que é armazenado dentro de outro documento.
O exemplo a seguir insere dois planetas em uma única chamada SaveChanges(). Como essa operação afeta mais de uma entidade raiz, o provedor a envolve automaticamente em uma transação. Se qualquer uma das inserções falhar, o fornecedor reverterá ambas as alterações.
Selecione a aba Synchronous ou Asynchronous para ver o código correspondente.
dbContext.Planets.AddRange( new Planet { Name = "Mercury" }, new Planet { Name = "Venus" } ); // Both inserts succeed or both are rolled back dbContext.SaveChanges();
dbContext.Planets.AddRange( new Planet { Name = "Mercury" }, new Planet { Name = "Venus" } ); // Both inserts succeed or both are rolled back await dbContext.SaveChangesAsync();
Configurar transações implícitas
A propriedade Database.AutoTransactionBehavior no seu objeto DbContext controla quando o fornecedor usa transações implícitas. Esta propriedade aceita um valor do enumeração do AutoTransactionBehavior , que contém os seguintes valores:
Valor | Descrição |
|---|---|
| O provedor usa uma transação somente quando |
| O provedor sempre usa uma transação, mesmo para operações de entidade única. |
| O provedor nunca usa uma transação. |
Você pode definir essa propriedade a qualquer ponto antes de chamar o método SaveChanges() ou SaveChangesAsync(), conforme mostrado no exemplo a seguir. Selecione a aba Synchronous ou Asynchronous para ver o código correspondente.
dbContext.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; // This SaveChanges() call will not use a transaction dbContext.Planets.Add(new Planet { Name = "Mars" }); dbContext.SaveChanges();
dbContext.Database.AutoTransactionBehavior = AutoTransactionBehavior.Never; // This SaveChangesAsync() call will not use a transaction dbContext.Planets.Add(new Planet { Name = "Mars" }); await dbContext.SaveChangesAsync();
Transações explícitas
Você pode usar transações explícitas para agrupar várias chamadas SaveChanges() e outras operações em uma única unidade atômica de trabalho. Para iniciar uma transação explícita, chame o método Database.BeginTransaction() ou Database.BeginTransactionAsync(). Depois de realizar suas operações, ligue para Commit() ou CommitAsync() para concluir a transação.
O exemplo a seguir mostra esse padrão envolvendo várias operações em uma única transação. Se alguma operação lançar uma exceção, o fornecedor reverterá automaticamente todas as alterações na transação. Selecione a aba Synchronous ou Asynchronous para ver o código correspondente.
using var transaction = dbContext.Database.BeginTransaction(); var planet = dbContext.Planets.First(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; dbContext.SaveChanges(); dbContext.Planets.Add(new Planet { Name = "Venus" }); dbContext.SaveChanges(); transaction.Commit();
await using var transaction = await dbContext.Database.BeginTransactionAsync(); var planet = await dbContext.Planets.FirstAsync(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; await dbContext.SaveChangesAsync(); dbContext.Planets.Add(new Planet { Name = "Venus" }); await dbContext.SaveChangesAsync(); await transaction.CommitAsync();
Dica
Reversão manual
Os exemplos nesta página usam uma declaração using para reverter automaticamente as transações e descartar os objetos de transação. Para reverter manualmente uma transação, chame o método Rollback() ou RollbackAsync() em um bloco catch.
Configurar transações explícitas
Você pode passar um objeto TransactionOptions para o método BeginTransaction() ou BeginTransactionAsync() para configurar a preocupação de leitura, preocupação de gravação, preferência de leitura e tempo máximo de confirmação para a transação.
A classe TransactionOptions tem as seguintes propriedades:
Propriedade | Tipo | Descrição |
|---|---|---|
|
| Leia a preocupação com o primeiro comando da transação. O valor padrão é |
|
| Preferência de leitura para operações de leitura na transação. As transações devem ler a partir do primário. O valor padrão é |
|
| Write concern para os comandos |
|
| Quantidade máxima de tempo para permitir que um único comando |
O exemplo a seguir inicia uma transação com um ReadConcern de Majority. Selecione a aba Synchronous ou Asynchronous para ver o código correspondente.
var options = new TransactionOptions( readConcern: new Optional<ReadConcern>(ReadConcern.Majority) ); using var transaction = dbContext.Database.BeginTransaction(options); var planet = dbContext.Planets.First(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; dbContext.SaveChanges(); transaction.Commit();
var options = new TransactionOptions( readConcern: new Optional<ReadConcern>(ReadConcern.Majority) ); await using var transaction = await dbContext.Database.BeginTransactionAsync(options); var planet = await dbContext.Planets.FirstAsync(p => p.Name == "Mercury"); planet.Name = "Mercury (Updated)"; await dbContext.SaveChangesAsync(); await transaction.CommitAsync();
Para saber mais sobre preocupação de leitura, preocupação de gravação e preferência de leitura,consulte Read Concern, Write Concern e Read Preference.
Limitações de transação
As seguintes limitações e avisos se aplicam quando você usa transações:
Desative as transações automáticas somente se seu sistema não as permitir. A desabilitação de transações automáticas pode levar a inconsistências de dados e impede que você use a simultaneidade otimista.
O MongoDB Server não suporta transações aninhadas. Se você chamar
BeginTransaction()ouBeginTransactionAsync()enquanto uma transação já estiver ativa, o fornecedor lançará umInvalidOperationException.O MongoDB Server não suporta pontos de gravação de transação. Você deve confirmar ou reverter uma transação inteira.
Por padrão, o MongoDB Server cancela qualquer transação que seja executada por mais de 60 segundos, conforme controlado pelo parâmetro
transactionLifetimeLimitSecondsservidor . Esse limite se aplica a transações implícitas e explícitas. Se sua transação exceder esse limite de tempo, o MongoDB Server a cancelará e o provedor lançará um erro. Evite realizar operações de longa duração, como chamadas de API externas, dentro de uma transação.Se o MongoDB Server sofrer uma interrupção de rede ou precisar executar uma eleição de conjunto de réplicas, ele poderá retornar um
TransientTransactionErrorerro. Nesses casos, o fornecedor de núcleo da EF não tenta novamente a transação automaticamente. Para saber mais sobre erros de transação transitórios e estratégias de repetição, consulte Tratamento de erros de transação.
Informações adicionais
Para saber mais sobre os conceitos deste guia, consulte os seguintes recursos:
Para saber mais sobre os métodos usados neste guia, consulte a seguinte documentação da API do .NET :