Is inheritance of navigation properties supported?

牧云@^-^@ 提交于 2019-12-07 13:44:46

问题


Having difficulty finding relevant search results...

Given this model:

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

With this configuration:

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

    base.OnModelCreating(modelBuilder);
}

I get this result in the DB:

Question:

Is inheritance of navigation properties not supported? If I add public string SomeSharedProperty { get; set; } to A then as I would expect the column for that property only showed up in the As table.

What reason is there for the Customer_ID column in the Bs and Cs table? Is there any way to tell EF to not map that inherited property?

Thanks!


回答1:


First off, inheritance is supported. But it seems in this specific instance not as you would expect.

Since Relational DBs do not support inheritance as we know it from object oriented programming there has to be some kind of transformation in order to make it happen.

Here is a series of blog post covering the issue in detail:

  • Table per hierarchy
  • Table per type
  • Table per class

It also tries to give guidelines when to use which of the strategies.

UPDATE
Apparently this is more tricky than it seemed at first glance. What you see is most likely due to a circular reference: A -> B -> Customer -> Bs.

The CustomerID columns of Bs/Cs are NOT the inherited ones from the As Table. It is in fact the representation of the relation properties specified on the Customer class:

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

results in a nullable CustomerID column on table B.

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

results in a nullable CustomerID column on table C.

So those nullable columns are used to represent the relation Customer -> Bs and Customer -> Cs. Their appearance has nothing to do with the Customer property on the A class.

You can easily check this by removing the navigation properties of the customer class. Then the result is what you would expect: A CustomerID column on the A table and no CustomerID column on B / C Table.

So in order to solve this you need to specifically tell EF how to resolve the circular reference. Not sure this is possible though, I'm afraid you will need to omit the Bs/Cs properties on the Customer and write a LINQ query instead to retrieve the info.

If you need those properties on the Customer class you can do is something like this:

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


来源:https://stackoverflow.com/questions/9648109/is-inheritance-of-navigation-properties-supported

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!