Le chiamate al servizio Web utilizzano il codice seguente per garantire che il chiamante abbia una sessione valida. Se viene trovata una sessione valida, aggiorna i dettagli della sessione e salva le modifiche. Tutto abbastanza semplice e funziona bene.Come impedire il deadlock di EntityFramework quando si eseguono contemporaneamente queste due istruzioni
// Create the Entity Framework context
using(MyContext ctx = CreateMyContext())
{
// Get the user session for the client session
UserSession session = (from us in context.UserSessions.Include("UserEntity")
where us.SessionId = callerSessionId
select us).FirstOrDefault<UserSession>();
if (session == null)
return false;
else
{
// Update session details
session.Calls++;
session.LastAccessed = DateTime.Now.Ticks;
Console.WriteLine("Call by User:{0}", session.UserEntity.Name);
// Save session changes back to the server
ctx.SaveChanges();
return true;
}
}
Tutto funziona bene fino a quando lo stesso utente, e quindi la stessa sessione, rende più chiamate simultanee (che è perfettamente valida per accadere). In questo caso a volte ho un punto morto. Utilizzando SQL Server Profiler posso vedere quanto segue sta accadendo.
Il chiamante A esegue la selezione e acquisisce un blocco condiviso nella sessione utente. Il chiamante B esegue la selezione e acquisisce un blocco condiviso sulla stessa sessione utente. Il chiamante A non può eseguire l'aggiornamento a causa del blocco condiviso del chiamante B. Il chiamante B non può eseguire l'aggiornamento a causa del blocco condiviso del chiamante A. Deadlock.
Questo sembra uno scenario di deadlock semplice e classico e deve esistere un metodo semplice per risolverlo. Sicuramente quasi tutte le applicazioni del mondo reale hanno lo stesso problema. Ma nessuno dei libri di Entity Frameworks ha menzionato qualcosa sui deadlock.
Posso fare una domanda su questo. L'uso (MyContext ctx ..) dovrebbe essere all'interno dell'uso (var scope = new TransactionScope) o viceversa? Grazie. – Raj
Credo che vorrai che il 'TransactionScope' si trovi all'interno di' MyContext'. Nella mia mente solo a pensarci ... poiché la Transazione viene utilizzata * per * il Contesto ... il Contesto deve esistere al termine della Transazione. Potrebbe essere sbagliato qui però. – Jared