EF Core报错:层次结构中所有实体类型需拥有相同所有权状态
解决EF Core中拥有实体继承层级所有权状态不匹配的问题
问题场景
在配置Casino和抽象基类Bonus的拥有关系时,派生类(如BonusMatch)标记为[Owned],但运行单元测试时抛出异常:
System.InvalidOperationException : Unable to set 'Bonus' as the base type for entity type 'BonusMatch' because 'BonusMatch' is configured as owned, while 'Bonus' is non-owned. All entity types in a hierarchy need to have the same ownership status.
相关实体和配置代码如下:
实体类代码
[Table("Casino")] public partial class Casino { private ICollection<Bonus> _bonuses; public ICollection<Bonus> Bonuses { get { return _bonuses; } set { _bonuses = value; } } } [Table("Bonus")] [Owned] public abstract class Bonus { private Casino _casino; public Casino Casino { get { return _casino; } set { _casino = value; } } } [Owned] public partial class BonusMatch : Bonus { // Match bonus properties }
配置代码
public class CasinoConfiguration : IEntityTypeConfiguration<Casino> { public void Configure(EntityTypeBuilder<Casino> modelBuilder) { modelBuilder.OwnsMany( c => c.Bonuses, b => { b.WithOwner(b => b.Casino).HasForeignKey("CasinoId"); b.Property<int>("Id"); b.HasKey("Id"); } ); } } public class BonusConfiguration : IEntityTypeConfiguration<Bonus> { public void Configure(EntityTypeBuilder<Bonus> modelBuilder) { modelBuilder.HasDiscriminator(d => d.SecondaryBonusType) .HasValue(typeof(BonusMatch), BonusTypes.Match) .HasValue(typeof(BonusFreeplay), BonusTypes.Freeplay) .HasValue(typeof(BonusNoDeposit), BonusTypes.NoDeposit) .HasValue(typeof(BonusPostWager), BonusTypes.PostWager) .HasValue(typeof(BonusCashback), BonusTypes.Cashback) ; modelBuilder .HasOne(b => b.Casino) .WithMany(c => c.Bonuses) .OnDelete(DeleteBehavior.Cascade); } }
解决方案
1. 调整实体类标记
- 移除
Bonus类上的[Owned]和[Table("Bonus")]特性:[Owned]会和OwnsMany的配置冲突,OwnsMany已经明确将Bonus标记为Casino的拥有实体;[Table]特性会强制EF将Bonus当作独立表的普通实体,违背拥有实体的语义。
- 给
Bonus类添加鉴别器字段(如SecondaryBonusType),用于EF识别派生类类型。
修改后的实体类:
[Table("Casino")] public partial class Casino { // 初始化集合避免空引用 private ICollection<Bonus> _bonuses = new List<Bonus>(); public ICollection<Bonus> Bonuses { get { return _bonuses; } set { _bonuses = value; } } } public abstract class Bonus { // 鉴别器字段,需和配置中的类型对应 public BonusTypes SecondaryBonusType { get; set; } private Casino _casino; public Casino Casino { get { return _casino; } set { _casino = value; } } } // 派生类无需标记[Owned],继承基类的拥有实体状态 public partial class BonusMatch : Bonus { // Match bonus properties }
2. 删除冗余的BonusConfiguration
BonusConfiguration中的HasOne/WithMany配置会将Bonus当作普通独立实体处理,覆盖OwnsMany的拥有实体设置,导致所有权状态冲突。删除该类,所有配置统一在CasinoConfiguration的OwnsMany lambda中完成。
3. 统一在OwnsMany中配置继承和关联
修改CasinoConfiguration,在OwnsMany的子配置中设置鉴别器、主键和所有者关联:
public class CasinoConfiguration : IEntityTypeConfiguration<Casino> { public void Configure(EntityTypeBuilder<Casino> modelBuilder) { modelBuilder.OwnsMany(c => c.Bonuses, b => { // 设置鉴别器,指定派生类对应的枚举值 b.HasDiscriminator<BonusTypes>("SecondaryBonusType") .HasValue<BonusMatch>(BonusTypes.Match) .HasValue<BonusFreeplay>(BonusTypes.Freeplay) .HasValue<BonusNoDeposit>(BonusTypes.NoDeposit) .HasValue<BonusPostWager>(BonusTypes.PostWager) .HasValue<BonusCashback>(BonusTypes.Cashback); // 设置拥有实体的主键 b.Property<int>("Id"); b.HasKey("Id"); // 关联所有者,EF会自动处理外键,也可显式指定名称 b.WithOwner(b => b.Casino); // 如需自定义外键名称,取消注释下面一行: // b.WithOwner(b => b.Casino).HasForeignKey("CasinoId"); }); } }
核心原因
你同时使用了两种冲突的配置方式:
OwnsMany将Bonus标记为Casino的拥有实体;BonusConfiguration中的HasOne/WithMany将Bonus当作普通独立实体配置关联。
这导致EF Core无法正确识别Bonus的所有权状态,而派生类BonusMatch又标记了[Owned],最终引发层级内所有权状态不匹配的异常。
内容的提问来源于stack exchange,提问作者Adam Hey
相关产品推荐
相关产品推荐

