Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Entity Framework concurrency issue using stored procedures

I am using ASP.NET to build a application for a retail company. I am using the Entity Framework (model-first) as my data access layer. I am using stored procedures to do my CRUD operations and all columns are mapped and seems to be correct as all CRUD functionality are working as expected.

But I am having concurrency issues with the DELETE operation.

I've added a TimeStamp column to the table I am doing the CRUD operation on. The UPDATE operation works fine as it is updating by primary key and the TimeStamp value. Thus if no rows are affected with the UPDATE operation, because of a change in the TimeStamp value, the Entity Framework throws a OptimisticConcurrencyException.

The DELETE operation works on the same principle as it is deleting by primary key and the TimeStamp value. But no exception is thrown when the TimeStamp value does not match between the entity and the database.

In the C# delete method I do retrieve the latest record first and then update the TimeStamp property to another TimeStamp value (It might be different to the retrieved value). After some investigation by using SQL Profiler I can see that the DELETE stored procedure is executed but the TimeStamp parameter that is passed to the stored procedure is the latest TimeStamp value and not the value that I have set the TimeStamp property to. Thus the record is deleted and the Entity Framework does not throw an exception.

Why would the Entity Framework still pass the retrieved TimeStamp value to the Stored Procedure and not the value that I have assigned the property? Is this be design or am I missing something?

Any help will be appreciated! (where is Julie Lerman when you need her! :-))

like image 588
Reynier Booysen Avatar asked Mar 24 '26 00:03

Reynier Booysen


1 Answers

Optimistic concurrency in EF works fine. Even with stored procedures.

ObjectContext.DeleteObjects passes original values of entity to delete function. This makes sense. Original values are used to identify the row to delete. When you delete object, you don't (usually) have meaningful edits to your entity. What do you expect EF to do with then? Write? To what records?

One legitimate use for passing modified data to delete function is when you want to track deletes in some other table and you need to throw in some information not accessible at database layer, only at business layer. Examples include application level user name or reason to delete. In this situation you need to construct entity with this values as original values. One way to do it:

var x = db.MyTable.Single(k => k.Id == id_to_delete);
x.UserName = logged_in_user;
x.ReasonForChange = some_reason;
// [...]
db.ObjectStateManager.ChangeObjectState(x, EntityState.Unchanged);
db.MyTable.DeleteObject(x);
db.SaveChanges();

Of course, better strategy might be to do it openly in business layer.


I don't understand your use case with rowversion/timestamp.

  1. To avoid concurrency issues you pass original timestamp to modifying code. That way it can be compared to current value in database to detect if record changed since you last read it. Comparing it with new value makes little sense.

  2. You usually use change markers that are automatically updated by database like rowversion/timestamp in SQL Server, rowversion in Oracle or xmin in PostgreSQL. You don't change its value in your code.

  3. Still, if you maintain row version manually, you need to provide:

    a) new version to insert and update to be written, and

    b) old version (read from database) to update and delete to check for concurrent changes.

    You don't send new value to delete. You don't need to. Also, when using stored procedures for modification, it's better to compute new version in the procedure and return it to application, not the other way around.

like image 194
Tomek Szpakowicz Avatar answered Mar 25 '26 13:03

Tomek Szpakowicz