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

时间:2012-03-10 16:34:12

标签: c# entity-framework ef-code-first

难以找到相关的搜索结果......

鉴于此模型:

public abstract class A
{
    public int ID { get; set; }
    public int CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}

public class B : A
{
}

public class C : A
{
}

public class Customer
{
    public int ID { get; set; }
    public virtual ICollection<B> Bs { get; set; }
    public virtual ICollection<C> Cs { get; set; }
}

使用此配置:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<A>().ToTable("As");
    modelBuilder.Entity<B>().ToTable("Bs");
    modelBuilder.Entity<C>().ToTable("Cs");

    base.OnModelCreating(modelBuilder);
}

我在数据库中得到了这个结果:

Database

问题:

是否不支持导航属性的继承?如果我将public string SomeSharedProperty { get; set; }添加到A,那么我希望该属性的列只显示在As表中。

Customer_IDBs表中Cs列的原因是什么?有没有办法告诉EF不映射那个继承的属性?

谢谢!

1 个答案:

答案 0 :(得分:3)

首先,支持继承。但在这个特定情况下,似乎并不像你期望的那样。

由于关系数据库不支持继承,因为我们从面向对象编程中知道它,因此必须进行某种转换才能实现。

这是一系列博客文章,详细介绍了这个问题:

它还试图给出何时使用哪种策略的指导。

<强>更新
显然这比初看起来更棘手。您看到的内容很可能是由于循环引用:A -> B -> Customer -> Bs

Bs / C的CustomerID列不是As表中的继承列。它实际上是Customer类中指定的关系属性的表示形式:

public virtual ICollection<B> Bs { get; set; }

会在表B中生成可为空的 CustomerID列。

public virtual ICollection<C> Cs { get; set; }

会在表C中生成可以为空的 CustomerID列。

因此,这些可以为空的列用于表示关系Customer -> BsCustomer -> Cs。它们的出现与Customer类的A属性无关。

您可以通过删除客户类的导航属性轻松进行检查。然后结果就是您所期望的:A表上的CustomerID列,B / C表上没有CustomerID列。

因此,为了解决这个问题,您需要具体告诉EF如何解决循环引用。不确定这是否可行,我担心你需要省略Customer上的Bs / Cs属性,而是写一个LINQ查询来检索信息。

如果您需要Customer课程上的这些属性,您可以这样做:

public class Customer
{
    public int ID { get; set; }

    // this is necessary to have access to the related Bs/Cs
    // also it cant be private otherwise EF will not overload it properly
    public virtual ICollection<A> As { get; set; }

    public IEnumerable<B> Bs { get { return this.As.OfType<B>(); } }
    public IEnumerable<C> Cs { get { return this.As.OfType<C>(); } }
}