EF6 no data in many-to-many table

asp.net-mvc c# entity-framework-6

Question

I'm learning ASP.NET MVC and EF with Getting Started with EF 6 using MVC 5 tutorial (Contoso University sample application). It's my first question here, so forgive me if the form of the question isn't perfect (tell me what's wrong anyway).

I've stuck with many to many relation. Table is created but no data inside.

I've added virtual navigation properties to both classes and set mappings in SchoolContext.

Course.cs

 public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Name = "Numer")]
        public int ID { get; set; }

        [StringLength(50, MinimumLength = 3)]
        [Display(Name = "Przedmiot")]
        public string Title { get; set; }

        [Range(0, 5)]
        [Display(Name = "ECTS")]
        public int Credits { get; set; }

        public int DepartmentID { get; set; }

        public virtual Department Department { get; set; }
        public virtual ICollection<Enrollment> Enrollments { get; set; }
        public virtual ICollection<Instructor> Instructors { get; set; }
    }

Instructor.cs

public class Instructor
    {
        public int ID { get; set; }

        [Required]
        [Display(Name = "Nazwisko")]
        [StringLength(50)]
        public string LastName { get; set; }

        [Required]
        [Column("FirstMidName")]
        [Display(Name = "ImiÄ™")]
        [StringLength(50)]
        public string FirstName { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Data zatrudnienia")]
        public DateTime HireDate { get; set; }

        public string FullName 
        { 
            get
            {
                return LastName + " " + FirstName;
            }
        }

        public virtual ICollection<Course> Courses { get; set; }
        public virtual OfficeAssignment OfficeAssignment { get; set; }
    }

SchoolContext.cs

public class SchoolContext : DbContext
    {
        public SchoolContext() : base("SchoolContext")
        {
        }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Department> Departments { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Instructor> Instructors { get; set; }
        public DbSet<Student> Students { get; set; }
        public DbSet<OfficeAssignment> OfficeAssignments { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
            modelBuilder.Entity<Course>()
              .HasMany(c => c.Instructors).WithMany(i => i.Courses)
              .Map(t => t.MapLeftKey("CourseID")
                  .MapRightKey("InstructorID")
                  .ToTable("CourseInstructor"));
        }
    } 

Data is initialized in Migrations/Configuration.cs in Seed() method:

protected override void Seed(MyUniversity.DAL.SchoolContext context)
{ (...) 
var instructors = new List<Instructor>
            {
                new Instructor { FirstName = "Antoni", LastName = "Czerwiński", HireDate = DateTime.Parse("2016-07-01")},
                new Instructor { FirstName = "Czesław", LastName = "Piotrowski", HireDate = DateTime.Parse("2016-07-01")},
                new Instructor { FirstName = "Paweł", LastName = "Andrzejewski", HireDate = DateTime.Parse("2016-07-01")},
                new Instructor { FirstName = "Karol", LastName = "Sokołowski", HireDate = DateTime.Parse("2016-07-01")},
                new Instructor { FirstName = "Alojzy", LastName = "Woźniak", HireDate = DateTime.Parse("2016-07-01")}
            };
            instructors.ForEach(s => context.Instructors.AddOrUpdate(p => p.LastName, s));
            context.SaveChanges();

var courses = new List<Course>
            {
                new Course { ID = 1050, Title = "Chemia", Credits =3,
                    DepartmentID = departments.Single(s => s.Name == "Inżynierii").ID, Instructors = new List<Instructor>() },
                new Course { ID = 4022, Title = "Mikroekonomia", Credits =3,
                    DepartmentID = departments.Single(s => s.Name == "Ekonomiczny").ID, Instructors = new List<Instructor>() },
                new Course { ID = 4041, Title = "Makroekonomia", Credits =3,
                    DepartmentID = departments.Single(s => s.Name == "Ekonomiczny").ID, Instructors = new List<Instructor>() },
                new Course { ID = 1045, Title = "Rachunek Różniczkowy", Credits =4,
                    DepartmentID = departments.Single(s => s.Name == "Matematyki").ID, Instructors = new List<Instructor>() },
                new Course { ID = 3141, Title = "Trygonometria", Credits =4,
                    DepartmentID = departments.Single(s => s.Name == "Matematyki").ID, Instructors = new List<Instructor>() },
                new Course { ID = 2021, Title = "Kompozycja", Credits =3,
                    DepartmentID = departments.Single(s => s.Name == "Anglistyki").ID, Instructors = new List<Instructor>() },
                new Course { ID = 2042, Title = "Literatura", Credits =4,
                    DepartmentID = departments.Single(s => s.Name == "Anglistyki").ID, Instructors = new List<Instructor>() }
            };
            courses.ForEach(s => context.Courses.AddOrUpdate(p => p.ID, s));
            context.SaveChanges();  
(...)
}

DbTablesRelationsImage

DbCourseInstructorTableImage

Here's link to the project on my github if needed: MyGithub

Edit(14:15)

I have method in Seed which is assigning Instructors to Courses. But question is why there's still no data in table?

protected override void Seed(MyUniversity.DAL.SchoolContext context)
{ (...) 
            AddOrUpdateInstructor(context, "Chemia", "Sokołowski");
            AddOrUpdateInstructor(context, "Chemia", "Andrzejewski");
            AddOrUpdateInstructor(context, "Mikroekonomia", "Woźniak");
            AddOrUpdateInstructor(context, "Makroekonomia", "Woźniak");

            AddOrUpdateInstructor(context, "Rachunek Różniczkowy", "Piotrowski");
            AddOrUpdateInstructor(context, "Trygonometria", "Andrzejewski");
            AddOrUpdateInstructor(context, "Kompozycja", "Czerwiński");
            AddOrUpdateInstructor(context, "Literatura", "Czerwiński");

            context.SaveChanges();
}

void AddOrUpdateInstructor(SchoolContext context, string courseTitle, string instructorName)
        {
            var crs = context.Courses.SingleOrDefault(c => c.Title == 
                courseTitle);
            var inst = context.Instructors.SingleOrDefault(i => i.LastName == 
                instructorName);
            if (inst == null)
            {
                crs.Instructors.Add(context.Instructors.Single(i => i.LastName == 
                instructorName));
            }
        }

1
0
4/2/2020 12:15:17 PM

Accepted Answer

At no point during seeding are you assigning Instructors to Courses; each Course is given an empty List of Instructors. So unless this is missing from your question, this is why the many-to-many table is empty.

0
4/2/2020 11:48:00 AM

Popular Answer

By default navigation properties are not loaded with a query.

For example:

using ( var context = new SchoolContext () ) {
    var professor = context.Instructors.FirstOrDefault();
    var courses = professor.Courses // this will be null even if there are linked courses.  
}

To fix this you can use Include().

For example:

using ( var context = new SchoolContext () ) {
    var professor = context.Instructors
        // this instructs EF to do the Join operation and include the Courses navigation property. 
        .Include ( prof => prof.Courses )   
        .FirstOrDefault();
    var courses = professor.Courses // this will now be populated with courses.  
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow