18 votes

Entity framework 5.0 gère-t-il les exceptions de concurrence optimiste ?

Lorsque l'on traite plusieurs exceptions potentielles au cours d'une context.SaveChanges() l'une des exceptions est OptimisticConcurrency . La documentation de Microsoft à ce sujet se trouve à l'adresse http://msdn.microsoft.com/en-us/library/bb399228.aspx discute de cela pour EF 4.x ...

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");
}

... mais avec EF 5.0 (RC), cela ne semble pas fonctionner car Refresh() n'existe pas sur mon EF5, code-first, dérivé de DbContext context classe.

Je vois. context.Entry(context.SalesOrderHeaders).Reload(); - mais il semble qu'il s'agisse d'un simple rechargement de la base de données et non d'un rafraîchissement ou d'une fusion (avec des gains de politique client).

Une idée sur la façon de gérer les exceptions de concurrence optimiste dans EF5 ? En fait, même des indications générales sur la gestion des exceptions dans SaveChanges() seraient les bienvenues.

Gracias

31voto

Ladislav Mrnka Points 218632

La façon de résoudre l'exception de concurrence dans l'API DbContext recharge l'entité originale :

catch (DbUpdateConcurrencyException ex)
{
    // Get failed entry
    var entry = ex.Entries.Single(...);
    // Overwrite original values with values from database but don't
    // touch current values where changes are held
    entry.OriginalValues.SetValues(entry.GetDatabaseValues());
}

Vous devriez également être en mesure d'utiliser le code mentionné mais vous devez obtenir ObjectContext de votre DbContext (il s'agit simplement d'une enveloppe autour de ObjectContext ).

catch (DbUpdateConcurrencyException ex)
{
    var objContext = ((IObjectContextAdapter)context).ObjectContext;
    // Get failed entry
    var entry = ex.Entries.Single(...);
    // Now call refresh on ObjectContext
    objContext.Refresh(RefreshMode.ClientWins, entry.Entity);        
}

Vous pouvez même essayer :

objContext.Refresh(RefreshMode.ClientWins, ex.Entries.Select(e => e.Entity));

1voto

Bronek Points 1476

Si vos modifications ne concernent qu'une seule entité (une ligne particulière, pas les autres tables, etc.), qui est couverte par le mécanisme de concurrence, vous êtes autorisé à rafraîchir le contexte en éliminant l'ancien et en créant un nouveau. Le problème est que lorsque le contexte est éliminé, toutes les entités modifiées et non encore validées sont détachées du contexte et les modifications sont perdues. Faites donc attention à la portée de votre travail unitaire !

    catch (DbUpdateConcurrencyException)
    {
        context.Dispose();
        context = new DBContext();
        Entity entity = context.Set<Entity>().Find(entityFromOldContext.Id);

        entity.Property1 = entityFromOldContext.Property1;
        entity.Property2 += 4;

        context.commit();
    }

Dans l'entité, j'utilise une propriété supplémentaire pour contrôler la concurrence comme suit :

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

Ce n'est peut-être pas une méthode élégante (et elle brise le modèle UnitOfWork), mais elle pourrait être utile dans certaines situations et enfin une alternative aux postes ci-dessus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X