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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 09:22:19