Entity Framework Optimistic Concurrency eccezione non si verificano
-
26-10-2019 - |
Domanda
Abbiamo un'applicazione ASP.Net MVC che utilizza EF4 come il suo livello di accesso ai dati e stiamo vedendo un comportamento imprevisto per quanto riguarda OptimisitcConcurrencyExceptions non essere gettati quando pensiamo che dovrebbero essere.
Abbiamo semplificato il problema verso il seguente codice ...
using System.Linq;
using Project.Model;
namespace OptimisticConcurrency
{
class Program
{
static void Main()
{
Contact firstContact = null;
using (var firstEntities = new ProjectEntities())
{
firstContact = (from c in firstEntities.Contacts
where c.LastName == "smith" select c).Single();
}
using (var secondEntities = new ProjectEntities())
{
var secondContact = (from c in secondEntities.Contacts
where c.LastName == "smith" select c).Single();
secondContact.Title = "a";
secondEntities.SaveChanges();
}
firstContact.Title = "b";
using (var thirdEntities = new ProjectEntities())
{
var thirdContact = (from c in thirdEntities.Contacts
where c.LastName == "smith" select c).Single();
thirdContact.Title = firstContact.Title;
//EXPLICITLY SET VERSION HERE
thirdContact.Version = firstContact.Version;
thirdEntities.SaveChanges();
}
}
}
}
Questa è una versione piuttosto semplice di ciò che accade nella nostra MVC app, ma lo stesso problema si verifica.
Quando chiamiamo SaveChanges sui thirdEntities, mi aspetto l'eccezione e nulla viene gettata.
Molto più interessante, quando si allega il Profiler SQL, vediamo che la versione viene utilizzato nella clausola WHERE ma è valore thirdEntities versione (quella attuale nel DB) in uso, non i valori firstEntities nonostante che sia esplicitamente impostare immediatamente prima SaveChanges si chiama. SaveChanges sta resettando la versione di essere il non valore recuperato il valore impostato.
Nel EDMX, la versione è impostato per avere uno StoreGeneratedPattern è impostato su computerizzata.
Qualcuno ha idea di cosa sta succedendo qui?
Soluzione
Questo è un problema. Una volta che la colonna è impostata su Computed
Non si può impostare il suo valore nell'applicazione (è possibile, ma il valore non è utilizzato).
Modifica
Se si carica un'entità dal database è di default rintracciato con il contesto. Il contesto memorizza i suoi valori originali. valori originali sono per esempio utilizzati per il cambiamento snapshot di monitoraggio, ma sono utilizzati anche come l'unica fonte valida di proprietà Computed
. Se si imposta la proprietà Computed
nel vostro soggetto il valore non viene utilizzato e il valore originale viene utilizzato insted. La soluzione è modificare il valore originale (prima di modificare qualsiasi altra cosa):
using (var context = new TestEntities())
{
var entityToUpdate = context.MyEntities.Single(e => e.Id == someId);
entityToUpdate.Timestamp = entity.Timestamp;
ObjectStateEntry entry = context.ObjectStateManager.GetObjectStateEntry(entityToUpdate);
entry.ApplyOriginalValues(entityToUpdate);
// set modified properties
context.SaveChanges();
}
Modifica 2:
Btw. una volta che avete sia effettivamente caricato timestamp e recuperati in precedenza timestamp si può semplicemente confrontarli nel vostro applicazione invece di farlo nel database.