Guardar los cambios y administrar la simultaneidad (Entity Framework)

De forma predeterminada, Entity Framework implementa un modelo de simultaneidad optimista. Esto significa que no se mantienen bloqueos sobre los datos del origen de datos entre el instante en que se consultan los datos y el instante en que son actualizados. Entity Framework guarda los cambios de los objetos en la base de datos sin comprobar la simultaneidad. Para entidades que pudieran experimentar un alto grado de simultaneidad, recomendamos que la entidad defina una propiedad en el nivel conceptual con un atributo ConcurrencyMode="fixed", como se muestra en el ejemplo siguiente:

<Property Name="Status" Type="Byte" Nullable="false" ConcurrencyMode="Fixed" />

Cuando se utiliza este atributo, Entity Framework comprueba si hay cambios en la base de datos antes de guardarlos en ella. Cualquier cambio en conflicto ocasionará una OptimisticConcurrencyException. Para obtener más información, vea Cómo administrar la simultaneidad de datos en un contexto del objeto (Entity Framework). También puede producirse una excepción OptimisticConcurrencyException cuando se define un modelo Entity Data Model que utiliza procedimientos almacenados para realizar actualizaciones en el origen de datos. En este caso, la excepción se produce cuando el procedimiento almacenado que se utiliza para realizar actualizaciones notifica que se actualizaron cero filas.

Cuando se realizan actualizaciones en escenarios de este tipo con una gran simultaneidad, ser recomienda llamar a Refresh con frecuencia. Al llamar a Refresh, el RefreshMode controla cómo se propagan los cambios. La opción StoreWins hará que Entity Framework sobrescriba todos los datos en la memoria caché de objetos con los valores correspondientes de la base de datos. A la inversa, la opción ClientWins reemplaza los valores originales en la memoria caché por los valores más recientes del origen de datos. De este modo se garantiza que todos datos modificados en la memoria caché de objetos pueden volverse a guardar correctamente en el origen de datos, eliminando los conflictos entre los cambios que se realizaron en los datos en la memoria caché y los cambios que se efectuaron en los mismos datos en el origen de datos.

Llame al método Refresh después de llamar al método SaveChanges si las actualizaciones en el origen de datos pueden modificar los datos que pertenecen a otros objetos en el contexto del objeto. Por ejemplo, en el modelo AdventureWorks Sales, cuando se agrega un nuevo SalesOrderDetail, se desencadena la actualización de la columna SubTotal para reflejar el subtotal con el nuevo elemento. En este caso, llame al método Refresh y pase el objeto SalesOrderHeader para el pedido. De este modo se garantiza que los valores generados por el desencadenador se devuelven al objeto SalesOrderHeader en el contexto del objeto.

Entity Framework realiza el seguimiento de los cambios que se han efectuado en los objetos de la memoria caché. Cuando se llama al método SaveChanges, Entity Framework intenta volver a combinar los cambios en el origen de datos. SaveChanges puede experimentar un error y producir una excepción OptimisticConcurrencyException cuando los cambios de datos en la memoria caché de objetos entran en conflicto con los cambios realizados en el origen de datos después de agregar o actualizar objetos en la memoria caché. Esto hace que toda la transacción se revierta. Cuando se produce una excepción OptimisticConcurrencyException, se debe controlar llamando a Refresh y especificando si el conflicto se debe resolver conservando los datos en los datos de objeto (StoreWins) o actualizando la memoria caché de objetos con los datos del origen de datos (ClientWins), como en el ejemplo siguiente:

Try
    ' Try to save changes, which may cause a conflict. 
    Dim num As Integer = context.SaveChanges()
    Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As OptimisticConcurrencyException
    ' Resolve the concurrency conflict by refreshing the 
    ' object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders)

    ' Save changes. 
    context.SaveChanges()
    Console.WriteLine("OptimisticConcurrencyException handled and changes saved")
End Try
try
{
    // Try to save changes, which may cause a conflict.
    int num = context.SaveChanges();
    Console.WriteLine("No conflicts. " +
        num.ToString() + " updates saved.");
}
catch (OptimisticConcurrencyException)
{
    // Resolve the concurrency conflict by refreshing the 
    // object context before re-saving changes. 
    context.Refresh(RefreshMode.ClientWins, orders);

    // Save changes.
    context.SaveChanges();
    Console.WriteLine("OptimisticConcurrencyException "
    + "handled and changes saved");
}

SaveChanges puede generar una excepción UpdateException cuando un objeto agregado a ObjectContext no se puede crear correctamente en el origen de datos. Esto puede suceder si ya existe una fila con la clave externa especificada por la relación. Cuando esto sucede, no se puede utilizar Refresh para actualizar el objeto agregado en el contexto del objeto. En su lugar, hay que recargar el objeto con un valor de OverwriteChanges para MergeOption.

Para obtener más información acerca de cómo administrar el contexto del objeto, vea Cómo administrar la simultaneidad de datos en un contexto del objeto (Entity Framework).

Puede optar por utilizar transacciones como alternativa a la simultaneidad optimista. Para obtener más información, vea Administrar conexiones y transacciones (Entity Framework).

En esta sección

Cómo administrar la simultaneidad de datos en un contexto del objeto (Entity Framework)

Vea también

Conceptos

Trabajar con objetos (Entity Framework)
Crear, agregar, modificar y eliminar objetos (Entity Framework)