12

I am using Entity Framework 6 with PostgreSQL. I have an entity in which I want to prevent concurrency issues, following this documentation I added a RowVersion property with [Timestamp] attribute, however after saving changes to the entity the column RowVersion value stays the same in the database.

    [Timestamp]
    public byte[] RowVersion { get; set; }

Am I missing something or is there another way to handle it in PostgreSQL?

3
  • I finally changed the byte[] RowVersion property for a string xmin property, specific to PostgreSQL, with ConcurrencyCheck decorator. Commented Mar 8, 2017 at 11:16
  • can you post the column definition? do you use npgsql to create the model? thanx Commented Sep 8, 2017 at 10:35
  • I've just posted the column definition as an answer Commented Sep 8, 2017 at 13:47

5 Answers 5

10
/// <summary>
/// Meant to validate concurrency en database update
/// This column is updates itself in database and only works in postgresql
/// </summary>
[ConcurrencyCheck]
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
//[NotMapped]
public string xmin { get; set; }

Had to add [NotMapped] attribute just for the column not to be added in the migration, commented it after database-update.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. Do you do this in a partial class? I am in a "database first" scenario
hi there, just remove the setter of the xmin property, instead of using the [NotMapped] attribute. it should not be migrated.
10

Just an updated answer for EF Core in case anyone else wanders here.

The Npgsql framework has built-in support for this using the hidden system column xmin that the OP is using in his entity as a NotMapped property.

As referenced here, you can set the xmin column as a concurrency token within EF by calling the UseXminAsConcurrencyToken method on your entity within its OnModelCreating method via Fluent API (a Data Annotation is not available at this time as far as I'm aware).

For anyone already using Fluent API configurations, it's as simple as this:

public class AwesomeEntityConfiguration : IEntityTypeConfiguration<AwesomeEntity>
{
    public void Configure(EntityTypeBuilder<AwesomeEntity> builder)
    {
        builder.UseXminAsConcurrencyToken();
    }
}

2 Comments

really awesome!
For real, this is great. Magic, even.
1

Based on postgresql documentation, xmin is one of the hidden columns in Postgres.

The thing that you need is to create a property with type uint and then : For Data Annotation :

public class SomeEntity
{
    public int Id { get; set; }

    [Timestamp]
    public uint Version { get; set; }
}

For 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; }
}

It maps version perpery to hidden xmin column. So there is no new column if you apply migration.

For more information, you can read npgsql docs about it.

Comments

0

Late 2024 update for Npgsql.EntityFrameworkCore.PostgreSQL 8.0.2. Method UseXminAsConcurrencyToken is obsolete now. It says:

Use EF Core's standard IsRowVersion() or [Timestamp], see https://learn.microsoft.com/ef/core/saving/concurrency

enter image description here

2 Comments

Please don't post code, exceptions, or results as images. They can't be copied and their "text" won't appear in search engines.
@GertArnold thank you. I have extracted all the valuable code above the image. I don't see anything else can be useful in image. Also this image has nice color scheme and uses new pretty-comment style from Rider
0

>= 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();
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.