EF Core使用TPC映射策略时为每个继承实体单独生成序列的实现方法
EF Core使用TPC映射策略时为每个继承实体单独生成序列的实现方法
我完全懂你现在的困扰——用TPC映射策略的时候,EF Core默认会给基类BaseEntity.Id生成一个全局序列,所有继承它的实体都共用这个序列来生成Id,但你希望每个实体表都有自己专属的独立序列。之前试的几种方法都踩了坑,我来给你分享两个可行的解决思路:
方法一:保留TPC继承结构,为每个子类配置专属序列
你不需要放弃原来的TPC基类配置,只需要在基类配置TPC之后,给每个子类的Id属性单独绑定专属序列即可。利用Npgsql的EF Core扩展方法就能实现:
首先保持你的基类和子类结构不变,然后在OnModelCreating里这样配置:
// 先给根实体BaseEntity配置TPC映射策略 modelBuilder.Entity<BaseEntity>().UseTpcMappingStrategy(); // 为Attribute实体配置专属序列 modelBuilder.Entity<Attribute>() .Property(e => e.Id) .UseNpgsqlIdentityColumn(seed: 1, increment: 1) .UseNpgsqlSequence("AttributeSequence"); // 为Practice实体配置专属序列 modelBuilder.Entity<Practice>() .Property(e => e.Id) .UseNpgsqlIdentityColumn(seed: 1, increment: 1) .UseNpgsqlSequence("PracticeSequence");
这个方法的核心是:虽然基类用了TPC,但我们通过Fluent API覆盖了每个子类Id的序列配置,让EF Core不再使用基类的全局序列,而是每个子类绑定自己的专属序列。
方法二:将基类改为普通C#基类(非EF实体),子类作为独立实体
如果上面的方法不符合你的预期,还可以换个思路:把BaseEntity从EF的实体体系中剥离,只作为普通的C#抽象基类来复用公共字段,每个子类作为独立的根实体,自己定义Id和序列。
1. 修改实体结构
// 普通C#抽象基类,不被EF视为实体 public abstract class BaseEntity { public DateTime DateUpdated { get; set; } public int TenancyId { get; set; } // 其他公共字段 } // Practice作为独立实体,自己定义主键Id public class Practice : BaseEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string Name { get; set; } } // Attribute作为独立实体,自己定义主键Id public class Attribute : BaseEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string Type { get; set; } }
2. 配置DbContext
在OnModelCreating里,不需要给BaseEntity做任何映射配置,直接给每个子类配置专属序列即可:
// 给Practice配置专属序列 modelBuilder.Entity<Practice>() .Property(e => e.Id) .UseNpgsqlSequence("PracticeSequence"); // 给Attribute配置专属序列 modelBuilder.Entity<Attribute>() .Property(e => e.Id) .UseNpgsqlSequence("AttributeSequence");
这样做之后,每个子类都是独立的EF实体,PostgreSQL会为每个实体的Id生成专属序列,完全不会有共用序列的问题。
为什么之前的方法会报错?
- 你尝试给子类配置
UseTpcMappingStrategy()报错:因为TPC是针对整个继承体系的映射策略,只能配置在继承链的根实体(也就是BaseEntity)上,子类不能单独配置。 - 你把
Id移到子类报错:因为当时BaseEntity还是被EF视为继承体系的根实体,EF Core要求TPC结构的主键必须定义在根实体上;而上面的方法二把BaseEntity排除在EF实体体系之外,子类变成了独立根实体,自然可以自己定义主键。
内容来源于stack exchange
相关产品推荐
相关产品推荐

