entity-frameworkentity-framework-6optimistic-concurrency

Handling DbUpdateConcurrencyException by simply aborting all operations


I'm new to the EF 6 and i'm trying to implement optimistic concurrency control , simply by alerting the user of the conflict and aborting all operations, i'm not interested in analysing the conflict, i just want to abort.

And by "all operations" i mean that the action will not be just a simple update but will have many crud operations, should i use a transaction to implement them, or should the context.SaveChanges be enough?

I mean when i reach context.SaveChanges and the DbUpdateConcurrencyException is thrown are all other operations rolled back automatically or should i code it myself.

Here is an example of the relevant piece of code :

// Get the record for User 1.
var User1 = context1.Purchases.First();
// Get the record for User 2.
var User2 = context2.Purchases.First();
// Make a change and save it for User 1.
User1.Amount = Convert.ToDecimal(7.99);
context1.SaveChanges();
try
{
  // Make a change and save it for User 2.
  User2.Amount = Convert.ToDecimal(10.99);
  context2.SaveChanges();
}
catch (DbUpdateConcurrencyException DUCE)
{
// Here i just want to abort everything and notify the user .
}
// Display a success message.
MessageBox.Show("Update Succeeded!");
}

Thank you.

I consider using context.Database.BeginTransaction to controll the flow of operations.


Solution

  • SaveChanges() already implements a Transaction across all changes so if you perform several updates on the DbContext and one of those updates fails for any reason, none of the updates will be committed, regardless of the exception that happens to get raised by SaveChanges().

    The question then becomes what to do with the DbContext and the tracked entities. When a DbContext throws an exception on SaveChanges due to something like invalid data state (FK constraint violations, data too large, etc.) the DbContext is now in a "poisoned" state. This means that it is still tracking those entities with the invalid data and there isn't really any way to know which of potentially many entities with changes have a problem. The simple answer in these cases is to dispose the DbContext and recreate it before trying again. EF Core supports discarding instances from change tracking on a DbContext instance, where in EF6 you can manually detach tracked, modified or added instances. In both cases any modified instances need to be reloaded to revert any modifications otherwise they still potentially contained poisoned data if you try to Attach them to a new DbContext intance or use Update.