Course contentsShow
← C#
Lesson 1046 of 1,90810. Entity Framework Core ModelingFree lesson

Concurrency Control with RowVersion

Implement optimistic concurrency patterns using byte-array tokens to prevent data collisions.

In this lesson, you will learn how to prevent "lost updates" in multi-user applications by implementing optimistic concurrency using RowVersion tokens.

The Concurrency Problem

Imagine two users open the same product record simultaneously. User A changes the price to 10,andUserBchangesthepriceto10, and User B changes the price to 12. If they both hit "Save" at the same time, the last person to save overwrites the other, and the first person’s changes vanish without warning. Optimistic concurrency assumes collisions are rare but provides a safety net to ensure we never overwrite data that has changed since we last read it.

Implementing RowVersion

To handle this, we use a byte[] property marked as a [Timestamp]. In SQL Server, this maps to a rowversion column, which the database automatically increments every time the row is updated.

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

How It Works

When you query a record, EF Core tracks the RowVersion value. When you call SaveChanges(), EF Core includes this token in the WHERE clause of the generated UPDATE statement:

UPDATE Products SET Price = @p1 WHERE Id = @id AND RowVersion = @originalVersion

If another user modified the row between your read and your write, the RowVersion in the database will have changed. Your update statement will fail to match any rows, and EF Core will throw a DbUpdateConcurrencyException.

Handling the Collision

When this exception occurs, your application should catch it, inform the user that the record was modified by someone else, and decide whether to reload the new data or force the overwrite. This pattern ensures that your database remains the "source of truth" and prevents accidental data loss during high-traffic scenarios.

Key Takeaway: By marking a byte-array property with the [Timestamp] attribute, you force EF Core to include it in update commands, ensuring the database rejects any save attempts based on stale, outdated information.