>= Npgsql v7.0
A lot of the answers here are outdated. Since Npgsql v7.0 (released in 9th November 2022) there is a new recommended approach.
First, let me say that Microsoft explicitly mentions in their EF Core docs that when using "native database-generated concurrency tokens" (i. e. rowversion for SQL Server, xmin for PostgreSQL etc.) the implementation is database specific.
Here quoted from MS Docs for EF Core: Hanlding concurrency conflicts - Native database-generated concurrency tokens:
The rowversion type shown above is a SQL Server-specific feature; the details on setting up an automatically-updating concurrency token differ across databases, and some databases don't support these at all (e.g. SQLite). Consult your provider documentation for the precise details.
So when you take that advice and have a look at the provider which is Npgsql for Postgres, they have very clear documentation on that.
Quoting from the Nggsql documentation:
Concurrency Tokens
[!NOTE]
Please read the general Entity Framework Core docs on concurrency tokens.
Entity Framework Core supports the concept of optimistic concurrency -
a property on your entity is designated as a concurrency token, and EF
Core detects concurrent modifications by checking whether that token
has changed since the entity was read.
The PostgreSQL xmin system column
Although applications can update concurrency tokens themselves, we
frequently rely on the database automatically updating a column on
update - a "last modified" timestamp, an SQL Server rowversion, etc.
Unfortunately PostgreSQL doesn't have such auto-updating columns - but
there is one feature that can be used for concurrency token. All
PostgreSQL tables have a set of implicit and hidden system
columns,
among which xmin holds the ID of the latest updating transaction.
Since this value automatically gets updated every time the row is
changed, it is ideal for use as a concurrency token.
Starting with version 7.0, you can map a uint property to the
PostgreSQL xmin system column using the standard EF Core mechanisms:
Data Annotations
public class SomeEntity {
public int Id { get; set; }
[Timestamp]
public uint Version { get; set; }
}
Fluent API
class MyContext : DbContext {
public DbSet<SomeEntity> SomeEntities { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeEntity>()
.Property(b => b.Version)
.IsRowVersion();
}
}
public class SomeEntity {
public int Id { get; set; }
public uint Version { get; set; }
}
In older version of the provider, use the following instead:
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Entity<Blog>().UseXminAsConcurrencyToken();
}