Evaluating the .NET Entity Framework I try to find the right patterns to handle concurrent updates with optimistic concurrency mode.
In the documentation and many other places I see the following pattern:
Try
' Try to save changes, which may cause a conflict.
Dim num As Integer = context.SaveChanges()
Console.WriteLine("No conflicts. " & num.ToString() & " updates saved.")
Catch generatedExceptionName As OptimisticConcurrencyException
' Resolve the concurrency conflict by refreshing the
' object context before re-saving changes.
context.Refresh(RefreshMode.ClientWins, orders)
' Save changes.
context.SaveChanges()
Console.WriteLine("OptimisticConcurrencyException handled and changes saved")
End Try
I see the following problems with this
- it automatically implements last-in-wins instead of using optimistic mode
- it is not robust: concurrent changes between .Refresh and .SaveChanges can cause a new OptimisticConcurrencyException
Is this correct, or am I missing something?
In a UI I normally let the user resolve the concurrency conflict:
Try
_ctx.SaveChanges()
Catch ex As OptimisticConcurrencyException
MessageBox.Show("Data was modified by another User." & vbCrLf &
"Click 'Refresh' to show the current values and reapply your changes.",
"Concurrency Violation", MessageBoxButton.OK)
End Try
In business logic I normally use a retry loop around the whole business transaction (reading and updating):
Const maxRetries = 5, retryDelayMs = 500
For i = 1 To maxRetries
Try
Using ctx As New EFConcurrencyTest.ConcurrencyTestEntities
ctx.Inventories.First.QuantityInStock += 1
System.Threading.Thread.Sleep(3000) 'Cause conflict
ctx.SaveChanges()
End Using
Exit For
Catch ex As OptimisticConcurrencyException
If i = maxRetries Then Throw
System.Threading.Thread.Sleep(retryDelayMs)
End Try
Next
With EF I plan to encapsulate the loop:
ExecuteOptimisticSubmitChanges(Of EFConcurrencyTest.ConcurrencyTestEntities)(
Sub(ctx)
ctx.Inventories.First.QuantityInStock += 1
System.Threading.Thread.Sleep(3000) 'Cause conflict
End Sub)
See: