You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在PostgreSQL中为EF Core 5配置支持备份恢复的并发令牌/行版本

实现可备份保留的并发检查功能方案

PostgreSQL的xmin是系统级事务标识列,属于元数据,备份恢复时必然会被重写,无法保留原值,你可以改用用户自定义的并发令牌列实现相同的行版本控制能力,自定义列属于普通业务列,pg_dump/pg_restore时会完整保留原值。
下面给出两种落地实现:

方案1:EF Core应用层自动维护(无需写数据库SQL)

步骤1:修改实体类,新增自定义版本列

public class Car {
    public Guid ID { get; set; }
    public string Model { get; set; }
    // 新增自定义并发版本列
    public int RowVersion { get; set; }
}

步骤2:修改OnModelCreating配置

modelBuilder.Entity<Car>(b =>
{
    b.Property(nameof(Car.ID)).IsRequired();
    // 配置自定义列为并发令牌,新增/更新时自动生成值
    b.Property(nameof(Car.RowVersion))
        .IsConcurrencyToken()
        .ValueGeneratedOnAddOrUpdate();
    b.ToTable("cars").HasKey(nameof(Car.ID));
});

步骤3:重写SaveChanges/SaveChangesAsync方法,自动更新版本号

在你的DbContext子类中添加如下逻辑:

public override int SaveChanges()
{
    foreach (var entry in ChangeTracker.Entries<Car>())
    {
        if (entry.State == EntityState.Added)
        {
            entry.Entity.RowVersion = 1;
        }
        else if (entry.State == EntityState.Modified)
        {
            entry.Entity.RowVersion += 1;
        }
    }
    return base.SaveChanges();
}
// 异步方法同理重写即可

该方案所有逻辑都在应用层实现,不需要修改数据库结构额外加触发器,适合小项目快速落地。

方案2:数据库端自动维护(更可靠,避免应用层漏更)

如果存在非EF Core的程序直接操作数据库的场景,推荐用数据库触发器自动维护版本列,保证所有更新场景下版本号都会更新。

步骤1:修改实体类,新增版本列

public class Car {
    public Guid ID { get; set; }
    public string Model { get; set; }
    public uint Version { get; set; }
}

步骤2:数据库创建版本自增函数和触发器

执行如下SQL:

-- 新建版本号自增函数
CREATE OR REPLACE FUNCTION increment_row_version()
RETURNS TRIGGER AS $$
BEGIN
    NEW.version = OLD.version + 1;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- 给cars表绑定更新触发器
CREATE TRIGGER trigger_car_increment_version
BEFORE UPDATE ON cars
FOR EACH ROW EXECUTE FUNCTION increment_row_version();

步骤3:EF Core配置

modelBuilder.Entity<Car>(b =>
{
    b.Property(c => c.ID).IsRequired();
    // 配置为并发令牌,插入时默认值为1,更新时由数据库自动生成新值
    b.Property(c => c.Version)
        .IsConcurrencyToken()
        .HasDefaultValue(1)
        .ValueGeneratedOnAddOrUpdate();
    b.ToTable("cars").HasKey(c => c.ID);
});

两种方案的并发冲突检测逻辑和原来用UseXminAsConcurrencyToken完全一致,更新时EF Core会自动在WHERE条件中带上原始版本号,匹配不到行时抛出DbUpdateConcurrencyException,原有业务代码不需要做大幅修改。

内容的提问来源于stack exchange,提问作者hunterex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 02:24:03