Search code examples
c#asp.netentity-frameworkef-code-firstcode-first

Entity Framework Code First navigation property through relational table


I'm trying to setup some navigation properties with some Entity Framework Code First models. I'd like them to look like this example:

public class Course
{
    [Key]
    public int CourseId { get; set; }
    public string CourseName { get; set; }
    public virtual ICollection<Student> Students { get; set; }
}

public class Student
{
    [Key]
    public int StudentId { get; set; }
    public string StudentName { get; set; }
    public virtual ICollection<Course> Courses { get; set; }
}

public class StudentCourses
{
    [Key, Column(Order = 0)]
    public int StudentId { get; set; }
    public virtual Student Student { get; set; }
    [Key, Column(Order = 1)]
    public int CourseId { get; set; }
    public virtual Course Course { get; set; }
}

So Student and Course relationships would be established in the StudentCourses table. An instance of the student class would automatically reference all of that students courses, and vice versa an instance of the Course class would automatically reference all of its Students. And an instance of the StudentCourses class would automatically reference its Student and Course. But when I try to Update-Database, the relationships don't seem to get properly interpreted. Is there anything I'm missing here? Perhaps some configuring needs to be done in the context class? Most of the examples of navigation properties just show one-to-many relationship navigation properties.


Solution

  • You need to construct your models as shown below when you have a M : M relationship. You don't need to construct junction table. EF will create one for you when you do the data migration.

    Model configuration using Conventions.

    public class Student
    {
        public Student() 
        {
            this.Courses = new HashSet<Course>();
        }
    
        public int StudentId { get; set; }
    
        public string StudentName { get; set; }
    
        public virtual ICollection<Course> Courses { get; set; }
    }
    
    public class Course
    {
        public Course()
        {
            this.Students = new HashSet<Student>();
        }
    
        public int CourseId { get; set; }
        public string CourseName { get; set; }
    
        public virtual ICollection<Student> Students { get; set; }
    }
    

    Your context class should be like this.

    public class YourDBContext : DBContext
    {
        public YourDBContext () : base("Default")
        {
        }
    
        public DbSet<Student> Students { get; set; }
    
        public DbSet<Course> Courses { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }
    }