In EF, this problem is solved by adding a Concurrency Token - the last time the row was modified. Then the save code for each of the users will check if the line has changed since the moment of loading:
public class Department { public int DepartmentID { get; set; } [StringLength(50, MinimumLength = 3)] public string Name { get; set; } // поле для отслеживания даты изменения [Timestamp] public byte[] RowVersion { get; set; } }
or, instead of the [Timestamp]
attribute, with the fluent configuration:
modelBuilder.Entity<Department>() .Property(p => p.RowVersion).IsConcurrencyToken();
EF will add a check that RowVersion has not changed to all generated Update
and Delete
types:
UPDATE ... SET A = 2 WHERE Id = @id AND @rowVersion = version1
The second possible solution is to place the attribute [ConcurrencyCheck]
on the "dangerous" properties. Then at Update / Delete the values of the marked properties will be checked. Those. in your case, the upgrade will look like
UPDATE ... SET A = 2 WHERE ID = @id AND A = 1
The first user update will be successful. For the second, SQL will update 0 rows, EF will detect this and throw DbUpdateConcurrencyException
or OptimisticConcurrencyException
that you will have to handle (for example, by repeating the action for the second user again).
The mechanism itself and the details of the processing are described in great detail in the standard tutorial Handling Concurrency with the Entity Framework 6