Entity Framework Core Concurrency (edit)
- Pessimistic Concurrency
- Optimistic Concurrency
- Entity Framework Core provides support for optimistic concurrency management
- Concurrency Token vs Timestamp (RowVersion)
- Concurrency Conflict
- Concurrency using xmin
- Usage of xmin column as concurrency token
Implementing optimistic concurrency with EF Core (dzimchuk.net)
- Optimistic Concurrency
Concurrency Management in Entity Framework Core | Learn Entity Framework Core
- Pessimistic Concurrency
- Optimistic Concurrency
Concurrency (entityframeworkcore.com)
The Code Blogger - Implement optimistic concurrency with .NET EF Core
Handling Concurrency in EF-Core - Learn Entity Framework Core 5
Current values: The present values that were last updated into the database by the user.
Original Values: The value that was present in the database initially, before concurrency occurred.
Database Value: The values that are currently stored in the database.
Giá trị hiện tại: Giá trị hiện tại được người dùng cập nhật lần cuối vào cơ sở dữ liệu.
Giá trị gốc: giá trị có trong cơ sở dữ liệu ban đầu, trước khi xảy ra đồng thời.
Giá trị cơ sở dữ liệu: Các giá trị hiện đang được lưu trữ trong cơ sở dữ liệu.
PostgreSQL
The PostgreSQL xmin system column
Concurrency Tokens | Npgsql Documentation
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>()
.UseXminAsConcurrencyToken();
class Blog
{
...
public uint xmin { get; set; }
}
PartsUnlimited : Optimistic Concurrency with PostgreSQL source (microsoft.github.io)
[SOLVED] => EF Core Postgres DbUpdateConcurrencyException when... (entityframeworkcore.com)
Usage of xmin column as concurrency token · Issue #19 · npgsql/efcore.pg (github.com)
Concurrency using xmin · Issue #179 · npgsql/efcore.pg (github.com)
modelBuilder.Entity<Person>().UseXminAsConcurrencyToken();
using System; using Microsoft.EntityFrameworkCore; namespace DataSetSerialization { internal class Program { private static void Main(string[] args) { var fooId = Guid.NewGuid(); using (var context = new TestContext()) { context.Add(new Person { Id = fooId, Name = "Foo", }); context.SaveChanges(); } using (var context = new TestContext()) { var wes = context.Find<Person>(fooId); wes.Name = "Bar"; context.Entry(wes).Property(x => x.XMin).OriginalValue = (uint) 1; // context.SaveChanges throws DbUpdateConcurrencyException context.SaveChanges(); } } } internal class TestContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseNpgsql("User ID=postgres;Password=xxxx;Host=localhost;Port=5432;Database=test;Pooling=true;"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Person>(b => { b.Property(x => x.XMin) .HasColumnName("xmin") .HasColumnType("xid") .ValueGeneratedOnAddOrUpdate() .IsConcurrencyToken(); }); base.OnModelCreating(modelBuilder); } } public class Person { public Guid Id { get; set; } public string Name { get; set; } public uint XMin { get; set; } } }