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
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:
Functional Optimistic Concurrency in C#
Retryable actions in C#
This:
Catch ex 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")
...is completely pointless. If the only thing you do when you "handle" the exception is to ignore it and save anyway, you should just turn optimistic concurrency off; you're writing code to work around an optional feature.
So, yes, I'd say the documentation is not giving you good advice here.
Your proposed UI code is a better solution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With