Concurrency-Exception-Handling fails
Situation: Pseudo-Code for handling Concurrency-Exception using(testScope = ...) { try { repository.Update(projekt); testScope.SaveChanges(); } catch (DbUpdateConcurrencyException ex) { foreach (var entry in ex.Entries) { entry.OriginalValues.SetValues(entry.GetDatabaseValues()); } testScope.SaveChanges(); //Retry to update Fails, because DbContextCollection says You can't call Commit() or Rollback() more than once on a DbContextCollection. }
What happens in DbContextCollection.cs "Commit"-method:
115 foreach (var dbContext in _initializedDbContexts.Values) 116 { 117 try 118 { 119 if (!_readOnly) 120 { 121 c += dbContext.SaveChanges(); 122 } 123 124 // If we've started an explicit database transaction, time to commit it now. 125 var tran = GetValueOrDefault(_transactions, dbContext); 126 if (tran != null) 127 { 128 tran.Commit(); 129 tran.Dispose(); 130 } 131 } 132 catch (Exception e) 133 { 134 lastError = ExceptionDispatchInfo.Capture(e); 135 } 136 } 137
138 transactions.Clear(); 139 completed = true; // *!!! in case of an exception this ist wrong. This Statement should be placed in line 130. *
That behaviour was implemented on purpose as I thought that there would be no valid situation where one would need to save changes more than once per scope (as this typically indicates a design issue).
But the scenario you presented is perfectly valid. It's true that if you use optimistic concurrency, you might want to re-try in case of concurrency issue. I completely overlooked this use-case.
I'll fix that ASAP.
Can this be closed? Is it fixed?
The commit above appears to fix the issue but has never been integrated into the main branch.
@mehdime - could this be merged and released in the next NuGet package?