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?