RowVersion and Timestamps in EF Core: Practical Guide for SQL Server

September 22, 2025 · 8 min

You add a RowVersion property to your entity, mark it with [Timestamp], and think you’re done with concurrency control. Then production hits: concurrency exceptions aren’t caught properly, API clients can’t handle the binary data, and you’re not sure if your timestamps are working.

SQL Server’s rowversion is powerful but has specific quirks that can trip up EF Core developers. Here’s how to implement it correctly.

Understanding SQL Server RowVersion

SQL Server’s rowversion is not a timestamp despite the old name. It’s an 8-byte binary value that automatically increments whenever any column in the row changes:

CREATE TABLE [Products] (
    [Id] int IDENTITY(1,1) NOT NULL,
    [Name] nvarchar(100) NOT NULL,
    [Price] decimal(18,2) NOT NULL,
    [RowVersion] rowversion NOT NULL,
    CONSTRAINT [PK_Products] PRIMARY KEY ([Id])
);

Every time you UPDATE this row, SQL Server automatically changes the RowVersion value. You never set it manually - the database engine handles everything.

EF Core RowVersion Implementation

The correct way to implement rowversion in EF Core:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    
    [Timestamp] // This maps to SQL Server rowversion
    public byte[] RowVersion { get; set; }
}

The [Timestamp] attribute tells EF Core this is a concurrency token that’s automatically generated by the database. EF Core …

Read more