Is inheritance of navigation properties supported?

Can't find any relevant search results ...

Considering 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 am getting this result in the DB:

Database

Question:

Navigation property inheritance not supported? If I add public string SomeSharedProperty { get; set; }

in A

, then, as I would expect, the column for that property only appears in the table As

.

What is the reason for the column Customer_ID

in the table Bs

and Cs

? Is there a way to tell EF not to display this inherited property?

Thank!

+3


source to share


1 answer


First, inheritance is supported. But it looks like this particular case is not what you expected.

Since relational databases do not support inheritance, since we know it from object-oriented programming, there must be some kind of transformation for this to happen.

Here is a series of blog posts detailing the issue:

He also tries to provide guidance on when to use which strategy.

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

.

The CustomerID

Bs / Cs columns are NOT inherited from the As table. In fact, this is a representation of the properties of the relations specified in the class Customer

:

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

      



results in a null column CustomerID

in table B.

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

      

leads to a column with a zero CustomerID

in Table C.

So these nullable columns are used to represent the relationship Customer -> Bs

and Customer -> Cs

. Their appearance has nothing to do with the property Customer

in the class A

.

You can check this easily by removing the navigation properties of the client class. Then the result is what you expect: column A CustomerID

in table A and column CustomerID

in table B / C.

So, to solve this problem, you need to specifically tell EF how to solve the circular reference. Not sure if this is possible, but I'm afraid you need to omit the Bs / Cs properties in Customer

and instead write a LINQ query to get the information.

If you need these properties in a class Customer

, you can do it 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>(); } }
}

      

+3


source







All Articles