Translate

viernes, 11 de octubre de 2013

Concurrencia optimista con Entity Framework

Concurrencia Optimista y Concurrencia Pesimista

Para este artículo es necesario comprender estos dos conceptos que son muy sencillos aunque el nombre haga pensar que es algo complejo. En entornos multiusuario donde se accede a una base de datos, por ejemplo un sitio  web. es común que dos o más personas estén editando algún campo de la base de datos al mismo tiempo.

Vamos a suponer que tenemos un sitio web y varios administradores editando campos de la base de datos y en ese momento dos de ellos están editando el mismo campo. El “Administrador A y el B”. Los dos comienzan a editar el campo al mismo tiempo, el “Administrador A” comienza a editar y luego se va a tomar un café, mientras que el “Administrador B“ edita y guarda rápidamente el campo modificado.

Al regresar el “Administrador A” no va a tener la información actualizada de la base de datos por lo que podrían producirse problemas futuros. En teoría hay dos formas de tratar con un escenario de este estilo aquí es donde aparecen los dos conceptos de concurrencia optimista y pesimista

En el caso de la concurrencia pesimista, nos dice que debemos permitir editar cualquier campo de la base de datos sólo a un usuario a la vez y bloquear el acceso al campo a cualquier otro usuario que intente editar el campo.

Desde mi punto de vista este tipo de concurrencia es problemática, tomando el ejemplo anterior, cualquier otro administrador debe esperar a que el “Administrador A” termine el café para poder editar el campo de la base de datos.

La concurrencia optimista, por otro lado es más permisiva ya que permite que cualquier usuario edite el campo de la base de datos y en caso de que se produzca alguna modificación mientras todavía editando se le informará al usuario de que se han producido cambios en la base de datos.

Si tomamos el ejemplo anterior, cuando el “Administrador A” regrese de tomarse el café e intente guardar el campo modificado el sistema le informará que el campo ha sido modificado y volverá a cargar la información actualizada de la base de datos o cualquier otra acción que se requiera.

Ejemplo

Para entender el ejemplo es necesario tener conocimientos básicos de Entity Framework y de Code First. Este link Get Started with Entity Framework (EF) tiene toda la información necesaria para comenzar.

Vamos a utilizar un modelo de dominio muy sencillo basado en una sola entidad “Game” juego que tiene dos propiedades el ID y el Nombre. Este ejemplo es también es válido para entidades más complejas.

Nota: El ejemplo está programado en Visual Studio 2012 utilizando Entity Framework 5 Code First. Puedes descargarlo desde el siguiente enlace: Ejemplo de EntityFramework y Concurrencia Optimista

Primero definimos la entidad Game

public class Game
{
    public int GameId { get; set; }
    public string Name { get; set; }
//Este campo va a ser usado por EF para chequear la concurrencia
    public byte[] RowVersion { get; set; }
}


Luego creamos la clase GameDbContext que nos va a permitir vincular nuestra base de datos con EF.

public class GameDbContext : DbContext
{
    public DbSet Games { get; set; }
}

El paso siguiente es informar a EF que la columna RowVersion sea utilizada para verificar que la fila no haya sido modificada. Esto lo podemos hacer de dos maneras con Anotaciones o utilizando “Fluent Api”.

Con anotaciones
Basta con decorar con la anotación Timestamp la propiedad RowVersion

[Timestamp]
public byte[] RowVersion { get; set; }

Con Fluent Api
Si no queremos “ensuciar” el modelo de dominio con anotaciones podemos utilizar “Fluent Api” Para ello debemos sobrescribir el método OnModelCreating de la clase GameDbContext y utilizar el método IsRowVersion() en la propiedad RowVersion.

public class GameDbContext : DbContext
{
    public DbSet Games { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity().Property(g => g.RowVersion).IsRowVersion();
    }
}

Ahora si cualquier campo de la fila ha sido modificado mientras otro usuario este editando EF generara la excepción “DbUpdateConcurrencyException”

try
{
    context.SaveChanges();
}
catch (DbUpdateConcurrencyException e)
{
//Manejar la excepcion
    Game newGame = ((Game)e.Entries.First().Entity);
    Console.WriteLine("La entidad ha sido modificada el nuevo nombre es: {0}", 

newGame.Name);
}

Cabe destacar que esta clase regresa en la propiedad e.Entries las entidades que fueron modificadas y el valor actual de la entidad.

El ejemplo del artículo es una aplicación de consola, hay que ejecutarla dos veces y luego pulsar cualquier tecla en una de las ventanas y después cualquier tecla en la otra. La última instancia va a intentar modificar el campo Game mientras que en la otra ventana ya se había modificado por lo que se producirá una excepción.

"Administrador A" Informamos que la entidad ha sido modificada


"Administrador B"

Saludos!.

Referencias
Utilizar concurrencia optimista

Get Started with Entity Framework (EF)

No hay comentarios:

Publicar un comentario