2013-03-27 10 views

risposta

16

Il modo standard sarebbe utilizzare la concorrenza ottimistica.

Dite, avete un semplice ente con un campo intero Counter che si desidera incrementare o decrementare:

public class SomeEntity 
{ 
    public int SomeEntityId { get; set; } 
    public int Counter { get; set; } 
} 

Si potrebbe segnare l'Counter poi come un token concorrenza. API Ottima è:

modelBuilder.Entity<SomeEntity>() 
    .Property(s => s.Counter) 
    .IsConcurrencyToken(); 

Quindi è possibile incrementare o decrementare il Counter per esempio in questo modo:

public void IncDecCounter(int someEntityId, bool dec) 
{ 
    using (var context = new MyContext()) 
    { 
     var someEntity = context.SomeEntities.Find(someEntityId); 
     if (someEntity != null) 
     { 
      bool saveFailed; 
      do 
      { 
       saveFailed = false; 

       if (dec) 
        --someEntity.Counter; 
       else 
        ++someEntity.Counter; 

       try 
       { 
        context.SaveChanges(); 
       } 
       catch (DbUpdateConcurrencyException e) 
       { 
        saveFailed = true; 
        e.Entries.Single().Reload(); 
       } 
      } while (saveFailed); 
     } 
    } 
} 

SaveChanges fallirà DbUpdateConcurrencyException se il valore della Counter quando l'entità è stata caricata (con Find in questo esempio, potrebbe essere qualsiasi altra query) si differenzia dal valore di Counter nel database quando l'istruzione UPDATE viene eseguita nel database, il che significherebbe che lo Counter è stato modificato da un altro utente i Nel frattempo Tecnicamente ciò è ottenuto da una clausola estesa WHERE dell'istruzione UPDATE generata che tenta di filtrare non solo dall'Id ma anche dal vecchio valore di Counter, in pratica qualcosa come: WHERE SomeEntityId = someEntityId AND Counter = oldCounterWhenTheEntityHasBeenLoaded.

Il blocco catch ricarica l'entità con il valore corrente Counter dal database e il ciclo successivo tenta di incrementare o decrementare nuovamente il valore ricaricato finché non riesce senza violazione della concorrenza.

+0

Grazie. ;-) Speriamo che sia abbastanza veloce (-; – NickD

+0

@Slauma, dove viene chiamato questo codice? 'ModelBuilder.Entity () .Property (s => s.Counter) .IsConcurrencyToken();' esegue il tuo soluzione ancora valida in EF6/6.1? E ultima cosa :) - Come ti avvicineresti a questo? Non ho ricevuto una risposta EF-Wise ... http://stackoverflow.com/questions/35825947/creating-object-counters-in-entity-framework-and-sql-server – ilans

Problemi correlati