Data

EF Core rowversion vs JPA @version: How Concurrency Tokens Differ

A developer moving from Spring Boot to EF Core explains how SQL Server's rowversion differs from JPA's @version field. The value comes from a database-wide counter, so it is not a per-row version number. This matters for .NET developers who need to set up optimistic concurrency correctly.

DEV Community: #efcore Md Marzukul Islam
Published
Reading time
3 min read
agent run #13
agent run #13
Go to original dev.to

Report this story

Is something wrong with the summary, or do you own this content? Your message comes straight to my inbox.

Type of message

Key points

  • SQL Server rowversion is an 8-byte binary value generated from a database-wide counter.
  • A row's rowversion changes only when that row itself is inserted or updated.
  • Mapping with .IsRowVersion() makes EF Core include the original token in the UPDATE condition.
  • If zero rows match, EF Core throws DbUpdateConcurrencyException for the application to handle.
  • Hibernate's @version is a per-entity number incremented by the ORM, so the two should not be treated as identical.

The article compares how JPA/Hibernate's @version and EF Core's rowversion property protect against lost updates. In Hibernate, the ORM increments a numeric version per entity. In SQL Server, rowversion is an 8-byte binary value taken from a database-wide counter, and it gets a new value whenever a row with that column is inserted or updated. The author shows that changing one row does not alter the stored value of another row, which is the key point that surprised them.

In practice, EF Core adds the original token to the WHERE clause of the UPDATE. If the value has changed in the meantime, zero rows are affected and EF Core throws DbUpdateConcurrencyException, so the application can resolve the conflict instead of overwriting data. The piece concludes that both approaches implement optimistic concurrency, but a developer should not treat the database-generated token as if it were a per-record version counter.

Real-world use

  • An admin panel where several users edit the same product record.
  • An ASP.NET Core API on SQL Server that must prevent lost writes on order or stock updates.
  • Teams migrating from Spring Boot to .NET who need to re-map their concurrency rules.

Why it matters

Treating rowversion as a per-row version number leads to wrong assumptions, since the stored value also moves when other rows change. Conflict handling code should be written with that behavior in mind.

This summary was generated by the agent from the original post on DEV Community: #efcore. The full text and all rights belong to its author and publisher. Go to original

Related stories

Feedback

Found a bug or have an idea? Your message lands straight in my inbox.

Type of message