I am using EF 6.x (code-first) on a Web API server with web clients and I need to implement concurrency handling. The problem is that I cannot even get EF to generate an exception.
Most examples that I have found seems to not be using "detached entities", where the DTO is sent to a web client where it is updated and then saved back to the server at a later time (which is my scenario).
Let's say I have a Company record:
public class Company
{
int CompanyId { get; set; }
string CompanyName { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
1) User A pulls up company with Id
= 0, RowVersion
is 0x0000000000002B0A
2) I run UPDATE Company SET CompanyName = 'Acme Changed, Inc.' WHERE CompanyId = 0
to simulate a change by another user. RowVersion
changes to 0x0000000000002B0B
3) User A changes CompanyName to "Acme, The Great!" and clicks Save (from browser)
4) The Company DTO arrives at Web API server with CompanyName
= "Acme, The Great!" and the old RowVersion
= 0x0000000000002B0A
5) I retrieve the Company record from the DB, update it and save it:
public void UpdateCompany(Company updatedCompany)
{
var dbCompany = Context.Companies.SingleOrDefault(r => r.CompanyId == updatedCompany.CompanyId);
dbCompany.CompanyName = updatedCompany.CompanyName;
dbCompany.RowVersion = updatedCompany.RowVersion; // Set RowVersion to the passed in original RowVersion 0x0000000000002B0A
try
{
DbContext.SaveChanges();
}
catch (DbUpdateConcurrencyException ex)
{
// Expected: exception thrown (but does not happen).
}
}
Instead of a concurrency exception, it just saves the record and updates RowVersion
to 0x0000000000002B0C.
What am I missing?
I need a way to detect changes, deletion, etc. to prevent saving dirty data. I guess I could roll my own checks, but the actual objects are complex with many nested child objects (one or more levels).
Any pointers on best practices on this would also be appreciated...
A DbUpdateConcurrencyException is thrown by SaveChanges when an optimistic concurrency exception is detected while attempting to save an entity that uses foreign key associations.
If you do want to implement this approach to concurrency, you have to mark all non-primary-key properties in the entity you want to track concurrency for by adding the ConcurrencyCheck attribute to them. That change enables the Entity Framework to include all columns in the SQL WHERE clause of UPDATE statements.
Entity Framework Core provides no support for pessimistic concurrency control.
I am working with an abstraction of Entity Framework and I don't have access to the EF context, but I found that writing
updatedCompany.RowVersion.CopyTo(dbCompany.RowVersion, 0);
solved the problem.
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