EF代码优先-继承和关系

本文关键字:继承 关系 代码 EF | 更新日期: 2023-09-27 18:27:38

请查看以下代码:

public class SomeEntity
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
}
public class SomeEntityA : SomeEntity
{
    public int Number { get; set; }
}
public class SomeEntityB : SomeEntity
{
    public string Text { get; set; }
}
public class User
{
    public int Id { get; set; }
    public int Username { get; set; }
    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; }
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; }
}

我的问题是,有没有一种方法可以设置FluentApi,使上面显示的关系正常工作?目前,当新的SomeEntityA对象被添加到User时,EF会在SomeEntity表中创建一个具有正确设置的User_Id FK的新记录,但在作为继承表的SomeEntitesA中,还有一个FK属性User_Id-设置为null,当我试图从User对象获取SomeEntitesA集合时,它是空的。我确实知道为什么会发生这种情况,但我不确定是否有办法解决这个问题?此时此刻,我想到的唯一解决方案是替换以下代码:

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; }
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; }

带有:

    public virtual ICollection<SomeEntity> SomeEntitiesA { get; set; }
    public virtual ICollection<SomeEntity> SomeEntitiesB { get; set; }

并配置FluentApi。

如有任何想法,我们将不胜感激。

EF代码优先-继承和关系

看看这个问题/答案,这些类的结构与您的完全相同,并且有一个详细的解释,解释了为什么事情没有按预期工作:

是否支持导航属性的继承?

正如Slauma所指出的,有一个相当简单的解决方案可以通过以下操作来解决这个问题(从链接的答案中复制并适合您的示例):

public class User
{
    public int Id { get; set; }
    public int Username { get; set; }
    // this is necessary to have access to the related SomeEntityAs/SomeEntityBs
    // also it cant be private otherwise EF will not overload it properly
    public virtual ICollection<SomeEntity> SomeEntities { get; set; }
    public IEnumerable<SomeEntityA> SomeEntitiesA { get { return this.SomeEntities.OfType<SomeEntityA>(); } }
    public IEnumerable<SomeEntityB> SomeEntitiesB { get { return this.SomeEntities.OfType<SomeEntityA>(); } }
}

您提出的解决方案也不起作用,因为您无法将两个导航属性User.SomeEntitiesAUser.SomeEntitiesB关联到同一个端点SomeEntity.User。您实际上需要两个用户:

public class SomeEntity
{
    public int Id { get; set; }
    public int UserAId { get; set; }
    [InverseProperty("SomeEntitiesA")]
    public virtual User UserA { get; set; }
    public int UserBId { get; set; }
    [InverseProperty("SomeEntitiesB")]
    public virtual User UserB { get; set; }
}

但是,您也可以保持集合类型的原样,并将用户移动到派生实体:

public class SomeEntity
{
    public int Id { get; set; }
}
public class SomeEntityA : SomeEntity
{
    public int Number { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
}
public class SomeEntityB : SomeEntity
{
    public string Text { get; set; }
    public int UserId { get; set; }
    public virtual User User { get; set; }
}
public class User
{
    public int Id { get; set; }
    public int Username { get; set; }
    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; }
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; }
}

在这种情况下,您不需要指定[InverseProperty],因为约定现在将检测到正确的导航属性对。