Mapping many to many relationship in entity framework code first

Lai32290 picture Lai32290 · Oct 28, 2013 · Viewed 37.9k times · Source

I'm try make a test in EF, creating a many to many relationship, because I always mapping One to One or One to Many, I has get a example in the internet for try, the example is working for insert registers, but I can't read registers

Here is my classes, I don't know what is HashSet, I get this code in the site

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public ICollection<Course> CoursesAttending { get; set; }

    public Person()
    {
        CoursesAttending = new HashSet<Course>();
    }
}

public class Course
{
    public int CourseId { get; set; }
    public string Title { get; set; }

    public ICollection<Person> Students { get; set; }

    public Course()
    {
        Students = new HashSet<Person>();
    }
}

Here is my Context

public class SchoolContext : DbContext
{
    public DbSet<Course> Courses { get; set; }
    public DbSet<Person> People { get; set; }

    public SchoolContext()
        : base("MyDb")
    {
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Course>().
            HasMany(c => c.Students).
            WithMany(p => p.CoursesAttending).
            Map(
                m =>
                {
                    m.MapLeftKey("CourseId");
                    m.MapRightKey("PersonId");
                    m.ToTable("PersonCourses");
                });

    }
}

When I insert registers is right

static void Main(string[] args)
{
    using (SchoolContext db = new SchoolContext())
    {
        Course math = new Course();
        Course history = new Course();
        Course biology = new Course();
        math.Title = "Math";
        history.Title = "History";
        biology.Title = "Biology";

        db.Courses.Add(math);
        db.Courses.Add(history);
        db.Courses.Add(biology);

        Person john = new Person();
        john.FirstName = "John";
        john.LastName = "Paul";
        john.CoursesAttending.Add(history);
        john.CoursesAttending.Add(biology);

        db.People.Add(john);
        db.SaveChanges();
    }
}

But when I try select register for show content, is not work, it just print nothing

static void Main(string[] args)
{
    using (SchoolContext db = new SchoolContext())
    {
        Pearson p = db.Peasons.First();
        Console.WriteLine(p.CoursesAttending.First().Title);
    }
}

I had check in the database, registers exist, what is the problem?

Please teach me how to make select in many to many relationship with code first.

Answer

Gert Arnold picture Gert Arnold · Oct 29, 2013

First off, you may want to enable lazy loading by making the collections virtual:

public virtual ICollection<Course> CoursesAttending { get; set; }
public virtual ICollection<Person> Students { get; set; }

This allows EF to create derived classes (proxies) from Course and Person that override the collections with logic to load their data from the data store.

When you do that you will see that

Console.WriteLine(p.CoursesAttending.First().Title);

will execute a separate query to populate CoursesAttending.

Alternatively, or additionally, you may decide to prevent round trips to the database by eager loading like so:

Person p = db.Persons.Include(p => p.CoursesAttending).First();

Which loads the Person and the CoursesAttending in one shot.