如何编写适配SQL Server与PostgreSQL的通用乐观并发Timestamp列
适配SQL Server和PostgreSQL的通用乐观并发实体类实现
可以通过EF Core的Fluent API配置+运行时数据库类型判断实现单一实体类适配两种数据库,无需维护多个分支。核心思路是在实体类中定义统一的版本属性,再根据当前使用的数据库提供程序,动态配置该属性的映射规则:
1. 定义通用实体类
选择ulong作为版本属性的类型(兼容SQL Server的8字节rowversion和PostgreSQL的xmin系统列):
public class DbEntity { // 主键及其他业务属性 public int Id { get; set; } public string Name { get; set; } // 统一的乐观并发版本属性 public ulong Version { get; set; } }
2. 在DbContext中配置数据库专属映射
重写OnModelCreating方法,根据数据库提供程序类型分别配置:
using Microsoft.EntityFrameworkCore; public class AppDbContext : DbContext { public DbSet<DbEntity> DbEntities { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // 根据环境配置对应数据库的连接字符串 // optionsBuilder.UseSqlServer("SQL_SERVER_CONN_STRING"); // 或 optionsBuilder.UseNpgsql("POSTGRESQL_CONN_STRING"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); var entityConfig = modelBuilder.Entity<DbEntity>(); // 判断当前数据库提供程序 if (Database.ProviderName == "Microsoft.EntityFrameworkCore.SqlServer") { // SQL Server:将ulong转换为byte[]映射到timestamp列,自动生成并作为并发令牌 entityConfig.Property(e => e.Version) .IsRowVersion() .HasConversion( ulongValue => BitConverter.GetBytes(ulongValue), byteArray => BitConverter.ToUInt64(byteArray, 0)) .HasColumnType("timestamp"); } else if (Database.ProviderName == "Npgsql.EntityFrameworkCore.PostgreSQL") { // PostgreSQL:映射到系统列xmin,自动生成并作为并发令牌 entityConfig.Property(e => e.Version) .HasColumnName("xmin") .HasColumnType("xid") .ValueGeneratedOnAddOrUpdate() .IsConcurrencyToken(); } } }
关键说明
- SQL Server端:
IsRowVersion()会自动将属性标记为并发令牌,数据库会自动维护timestamp列的递增,无需手动赋值。通过类型转换将ulong与byte[]互转,保证实体类类型统一。 - PostgreSQL端:直接映射到内置的
xmin系统列(该列记录行的版本号,每次更新自动递增),无需手动创建数据库列,ValueGeneratedOnAddOrUpdate()和IsConcurrencyToken()确保EF Core将其用作乐观并发校验。 - 无需修改实体类代码,仅通过DbContext配置适配不同数据库,同一代码库可直接切换SQL Server/PostgreSQL连接字符串使用。
内容的提问来源于stack exchange,提问作者Alex T
相关产品推荐
相关产品推荐

