Seed in Entity Framework Core Many-to-Many

.net-core asp.net-core c# entity-framework entity-framework-core

Question

how can one seed a many-to-many relation in EF Core, couldn't find anything in this area?

So this is the entities

public class Student 
{
     public int Id { get; set; }
     public string Name { get; set; }

     public virtual List<StudentGrade> StudentGrades { get; set; }
}


public class Grade 
{
     public int Id { get; set; }
     public int Grade { get; set; }

     public virtual List<StudentGrade> StudentGrades { get; set; }
}


public class StudentGrade 
{
     public int GradeId { get; set; }
     public Grade Grade { get; set; }

     public int StudentId { get; set; }
     public Student Student { get; set; }
}

so the official documentation says you have to have a joining entity defined (in my case StudentGrade) and this should be referenced within the entities that are in a many-to-many relation. Ef core documentation for many-to-many.

Now in EF, you wouldn't have to do this, it would figure out those things, and so instead of having the join-entity, you would simply reference each entity into the other.

So how can you seed this type of relation in EF Core?

Thanks

1
6
9/28/2018 1:25:53 PM

Accepted Answer

So what worked for me was overriding DbContext::OnModelCreating(ModelBuilder modelBuilder) with something similar to this:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
       modelBuilder.Entity<StudentGrade>()
                    .HasKey(s => new { s.GradeId , s.StudentId });
    var students= new[]
    {
     new Student{Id=1, Name="John"},
     new Student{Id=2, Name="Alex"},
     new Student{Id=3, Name="Tom"}
    }

    var grades = new[]
    {
     new Grade{Id=1, Grade=5},
     new Grade{Id=2, Grade=6}
    }

    var studentGrades = new[]
    {
     new StudentGrade{GradeId=1, StudentId=1},
     new StudentGrade{GradeId=2, StudentId=2},

     // Student 3 relates to grade 1 
     new StudentGrade{GradeId=1, StudentId=3}
    }

    modelBuilder.Entity<Student>().HasData(stdudents[0],students[1],students[2]);
    modelBuilder.Entity<Grade>().HasData(grades[0],grades[1]);
    modelBuilder.Entity<StudentGrade>().HasData(studentGrades[0],studentGrades[1],studentGrades[2]);

    base.OnModelCreating( modelBuilder );
}
5
4/15/2020 6:51:38 PM

Popular Answer

I've followed the custom initialization logic, as explained here, since my commitment is just data for testing and developing.

I like to do the seeding in a synchronous way, as you'll see in the code.

Important: Previous to this step, I do a 'commit' (context.SaveChanges();) with the entities data that I have to join, so EF will pick them from the DB with the ID inserted. That's nice if the DB backend has an autoincremental ID.

Following with your example (I've pluralized the dbSets), and assuming you have inserted the proper data

    var student= context.Students.FirstOrDefault(a => a.Name == "vic");
    var grade= context.Grades.FirstOrDefault(b => b.Grade == 2);
    var studentGrade = context.StudentsGrades.Include(a => a.Students).Include(b => b.Grades)
               .FirstOrDefault(c => c.Students.Name == "vic" && c.Grades.Grade = 2);
    if (studentGrade == null)
    {
        context.StudentsGrades.Add(new StudentGrade 
        {                    
            StudentId = student.Id,
            GradeId = grade.Id
        });
    }

    context.SaveChanges();


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