Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF not throwing DbUpdateConcurrencyException despite conflicting updates

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...

like image 352
Lars335 Avatar asked Jun 17 '17 22:06

Lars335


People also ask

Which type of exception is thrown by EF when the database is concurrently updated?

A DbUpdateConcurrencyException is thrown by SaveChanges when an optimistic concurrency exception is detected while attempting to save an entity that uses foreign key associations.

How do you configure entity framework for optimistic concurrency?

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.

Which concurrency approach is not supported in EF core?

Entity Framework Core provides no support for pessimistic concurrency control.


1 Answers

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.

like image 197
Richard Avatar answered Sep 28 '22 06:09

Richard