【问题标题】:Is inheritance of navigation properties supported?是否支持导航属性的继承?
【发布时间】:2012-03-11 05:22:33
【问题描述】:

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

鉴于此模型:

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);
}

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

问题:

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

BsCs 表中的Customer_ID 列是什么原因?有没有办法告诉 EF 不要映射该继承属性?

谢谢!

【问题讨论】:

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


    【解决方案1】:

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

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

    这是一系列详细介绍该问题的博客文章:

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

    更新
    显然,这比乍看之下更棘手。您看到的很可能是由于循环引用:A -&gt; B -&gt; Customer -&gt; Bs

    Bs/Cs 的CustomerID 列不是从 As Table 继承的。它实际上是在Customer 类上指定的关系属性的表示:

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

    导致表 B 上的 可为空 CustomerID 列。

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

    导致表 C 上的 可为空 CustomerID 列。

    所以那些可以为空的列用于表示关系Customer -&gt; BsCustomer -&gt; Cs。它们的外观与A 类上的Customer 属性无关。

    您可以通过删除客户类的导航属性轻松检查这一点。那么结果就是你所期望的: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>(); } }
    }
    

    【讨论】:

    • 您可以在我的配置中看到我正在使用 TPT 继承映射。我以前读过所有这些文章。我的具体问题是为什么 CustomerID 外键列出现在所有 3 个表中,是否有任何方法可以防止这种情况发生。
    • 我的猜测是,通过使 Customer 属性 virtual 导致 EF 假设关系可能在 B 和 C 上以不同方式处理,因此它也将属性移动到这些类,尝试如果您不希望发生这种情况,请删除 virtual 关键字。
    • 不工作意味着它不能编译或者它不能产生你期望的 SQL 表?同样,现在如何完成并没有错,只是与您的预期不同。层次结构已正确转换。这是要求与众不同还是只是觉得现在这样做是错误的?
    • 它不会更改 SQL 表。它是如何完成的是错误的。使用 TPT 的全部意义在于规范化您的数据。没有理由使用 3 个 CustomerID 属性。 As 表上应该只有一个。
    • 这实际上不是继承问题,您看到的属性是代表Customer -&gt; Bs/Cs 之间的关系。我已更新我的答案以反映我运行的测试以确认这确实发生了。
    猜你喜欢
    • 2016-11-13
    • 2011-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多