Para agentes de IA: hay un índice de documentación disponible en https://www.mongodb.com/es/docs/llms.txt — versiones en markdown de todas las páginas están disponibles agregando .md a cualquier ruta URL.
Docs Menu

Cambios por lotes con transacciones

En esta guía, puedes aprender a usar transacciones en tus aplicaciones EF Core Provider. Una transacción envuelve una serie de operaciones de guardar. Si alguna operación en la transacción falla, el proveedor revierte todos los cambios en la transacción. Este comportamiento ayuda a garantizar la coherencia de los datos.

El proveedor EF Core es compatible con los siguientes modos de transacción:

  • Transacciones implícitas: El proveedor envuelve automáticamente las llamadas a los métodos SaveChanges() y SaveChangesAsync() en una transacción. Consulta Configurar transacciones implícitas para aprender cómo configurar o deshabilitar este comportamiento.

  • Transacciones explícitas: Se llama al método Database.BeginTransaction() para iniciar manualmente una transacción, y luego se confirma o revierte la transacción llamando a Commit() o Rollback().

Los ejemplos de esta guía utilizan la colección planets de la base de datos sample_guides. Los documentos de esta colección utilizan la siguiente clase Planet como 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; }
}

Esta colección proviene de los conjuntos de datos de ejemplo proporcionados por Atlas. Consulta la guía «Primeros pasos con el proveedor de EF Core» para aprender a crear un clúster de MongoDB gratuito y cargar estos datos de ejemplo.

Antes de usar transacciones, ten en cuenta los siguientes requisitos y limitaciones:

  • Las transacciones requieren una implementación de MongoDB Server que admita transacción multi-documento, como un set de réplicas o clúster. Si su aplicación intenta iniciar una transacción en una implementación independiente, el proveedor arroja un NotSupportedException. Para evitar esto, configure AutoTransactionBehavior.Never como se describe en Configurar transacciones implícitas.

  • El proveedor de EF Core no admite transacciones ambientales de .NET, como las creadas por System.Transactions.TransactionScope. Si intentas usar una transacción ambiental, el proveedor lanza una excepción. Utiliza transacciones implícitas o explícitas en su lugar.

De manera por defecto, el Proveedor de EF Core envuelve automáticamente las llamadas SaveChanges() y SaveChangesAsync() en una transacción cuando se ven afectados varios Entidades raíz. Una entidad raíz es un documento de nivel superior en una colección, a diferencia de un tipo poseído o incrustado que se almacena dentro de otro documento.

El siguiente ejemplo inserta dos planetas en una única llamada de SaveChanges(). Porque esta operación afecta a más de una entidad raíz, el proveedor la envuelve automáticamente en una transacción. Si alguno de los insertos falla, el proveedor revierte ambos cambios.

Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

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();

La propiedad Database.AutoTransactionBehavior en su objeto DbContext controla cuándo el proveedor utiliza transacciones implícitas. Esta propiedad acepta un valor del enum AutoTransactionBehavior, que contiene los siguientes valores:

Valor
Descripción

WhenNeeded

El proveedor utiliza una transacción solo cuando SaveChanges() o SaveChangesAsync() afectan a más de una entidad raíz. Este es el valor por defecto.

Always

El proveedor siempre utiliza una transacción, incluso para operaciones de una sola entidad.

Never

El proveedor nunca utiliza una transacción.

Puede establecer esta propiedad en cualquier momento antes de llamar al método SaveChanges() o SaveChangesAsync(), como se muestra en el siguiente ejemplo. Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

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();

Puedes utilizar transacciones explícitas para agrupar múltiples llamadas SaveChanges() y otras operaciones en una única unidad atómica de trabajo. Para iniciar una transacción explícita, llama al método Database.BeginTransaction() o Database.BeginTransactionAsync(). Después de realizar tus operaciones, llama al Commit() o CommitAsync() para completar la transacción.

El siguiente ejemplo muestra este patrón al agrupar múltiples operaciones en una única transacción. Si alguna operación arroja una excepción, el proveedor revierte automáticamente todos los cambios en la transacción. Seleccione la pestaña Synchronous o Asynchronous para ver el código correspondiente.

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();

Tip

Manual Rollback

Los ejemplos de esta página utilizan una declaración using para revertir automáticamente transacciones y liberar los objetos de la transacción. Para revertir manualmente una transacción, llama al método Rollback() o RollbackAsync() en un bloque catch.

Puede pasar un TransactionOptions objeto al método BeginTransaction() o BeginTransactionAsync() para configurar el nivel de consistencia de lectura, el nivel de confirmación de escritura (write concern), la preferencia de lectura y el tiempo máximo de compromiso para la transacción.

La clase TransactionOptions tiene las siguientes propiedades:

Propiedad
Tipo
Descripción

ReadConcern

ReadConcern

Nivel de consistencia de lectura para el primer comando en la transacción. El valor por defecto es null. Si no configuras esta propiedad, el proveedor hereda el valor de las opciones de transacción por defecto de la sesión o de los MongoClient.

ReadPreference

ReadPreference

Preferencia de lectura para operaciones de lectura en la transacción. Las transacciones deben leer desde el primario. El valor por defecto es null. Si no se configura esta propiedad, el proveedor hereda el valor de las opciones de transacción predeterminadas de la sesión o de MongoClient.

WriteConcern

WriteConcern

Nivel de confirmación de escritura (write concern) para los comandos commitTransaction y abortTransaction. El valor predeterminado es null. Si no se establece esta propiedad, el proveedor hereda el valor de las opciones de transacción por defecto de la sesión o del MongoClient.

MaxCommitTime

TimeSpan?

Cantidad máxima de tiempo que se permite ejecutar un solo comando commitTransaction. La opción por defecto es null. Si no configuras esta propiedad, el proveedor no enviará un límite de tiempo de commit.

El siguiente ejemplo inicia una transacción con un ReadConcern de Majority. Selecciona la pestaña Synchronous o Asynchronous para ver el código correspondiente.

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 obtener más información sobre el nivel de consistencia de lectura, nivel de confirmación de escritura (write concern) y preferencia de lectura, consulte nivel de consistencia de lectura, nivel de confirmación de escritura (write concern) y preferencia de lectura.

Se aplican las siguientes limitaciones y advertencias cuando usas transacciones:

  • Desactive las transacciones automáticas sólo si su implementación no las admite. Desactivar las transacciones automáticas puede provocar inconsistencias en los datos y evitar que uses concurrencia optimista.

  • El servidor de MongoDB no admite transacciones anidadas. Si llamas a BeginTransaction() o BeginTransactionAsync() mientras una transacción ya está activa, el proveedor lanza un InvalidOperationException.

  • El servidor de MongoDB Server no admite puntos de guardado de transacciones. Debe confirmar o revertir una transacción completa.

  • Por defecto, MongoDB Server aborta cualquier transacción que se ejecute durante más de 60 segundos, según lo controlado por el parámetro del servidor transactionLifetimeLimitSeconds. Este límite se aplica a las transacciones tanto implícitas como explícitas. Si su transacción supera este límite de tiempo, el MongoDB Server la interrumpe y el proveedor muestra un error. Evite realizar operaciones de larga duración, como llamadas a API externas, dentro de una transacción.

  • Si el MongoDB Server experimenta una interrupción de la red o debe realizar una elección de set de réplicas, podría devolver un error TransientTransactionError. En estos casos, el proveedor EF Core no reintenta automáticamente la transacción. Para obtener más información sobre errores transitorios en transacciones y estrategias de reintento, consulta Manejo de Errores de Transacciones.

Para aprender más sobre los conceptos de esta guía, consulta los siguientes recursos:

Para obtener más información sobre los métodos utilizados en esta guía, consulte la siguiente documentación de la API de .NET: