Entity Framework Code First Many-to-Many relationship and inheritance

asp.net-mvc-4, ef-code-first, entity-framework-5

Solution

You cannot inherit navigation properties from a base entity. They always must be declared in the class the other end of the relationship is refering to.

- `Template.Customers` is refering to `Customer` (not to `Person`), hence the inverse navigation property `Templates` must be declared in `Customer` (not in `Person`)

- `Template.User` is refering to `User` (not to `Person`), hence the inverse navigation property `Templates` must be declared in `User` (not in `Person`)

So, basically you must move the `Templates` collection from `Person` into both derived classes:

public class Person
{
    // no Templates collection here
}

public class User : Person
{
    //... 
    public virtual List<Template> Templates { get; set; }
}

public class Customer : Person
{
    //...
    public virtual List<Template> Templates { get; set; }
}

Then you can define the two relationships with Fluent API like so:

modelBuilder.Entity<Template>()
    .HasMany(t => t.Customers)
    .WithMany(c => c.Templates) // = Customer.Templates
    .Map(x => x.MapLeftKey("TemplateId")
               .MapRightKey("PersonId")
               .ToTable("TemplateCustomer"));

modelBuilder.Entity<Template>()
    .HasRequired(t => t.User)
    .WithMany(u => u.Templates) // = User.Templates
    .HasForeignKey(t => t.UserId);

Problem

Forgive me if this question has been answered somewhere, I have been having a hard time finding a solution for this problem. I am trying to set up EF Code First on an MVC4 Project. I have a User and Customer that both inherit from Person. I then have a Template object that has a Many-to-Many relationship with Customer and a One-to-Many relationship with User. Here is how I have it set up: MODELS ``` public class Person { [Key] public int PersonID { get; set; } public string LastName { get; set; } public string FirstName { get; set; } public string FullName { get { return String.Format("{0} {1}", FirstName, LastName); } } public string Email { get; set; } public virtual List<Template> Templates { get; set; } } public class User : Person { .... } public class Customer : Person { .... } public class Template { public int TemplateId { get; set; } public string TemplateName { get; set; } public virtual List<Customer> Customers { get; set; } [ForeignKey("User")] public int UserId { get; set; } public virtual User User { get; set; } } ``` CONTEXT ``` public class ProjectContext : DbContext { public ProjectContext() : base("name=ProjectDB") { } public DbSet<Template> Templates { get; set; } public DbSet<User> Users { get; set; } public DbSet<Customer> Customers { get; set; } public DbSet<Person> People { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions .Remove<PluralizingTableNameConvention>(); modelBuilder.Entity<Template>() .HasMany(x => x.Customers) .WithMany(x => x.Templates) .Map(x => x.MapLeftKey("TemplateId") .MapRightKey("PersonId") .ToTable("TemplateCustomer") ); } } ``` If I remove the Person DBSet out of the context this works fine but sets up TPT inheritance. I would like to use TPH inheritance, but when I enable migrations with the Person DBSet in the context it chokes: NavigationProperty 'Templates' is not valid. Type 'MvcProject.Models.Customer' of FromRole 'Template_Customers_Target' in AssociationType 'MvcProject.Models.Template_Customers' must exactly match with the type 'MvcProject.Models.Person' on which this NavigationProperty is declared on. Where am I going wrong here?

Original source