Entity Framework 6 Refresher: Many To Many Referencing Self

1 minute read

Occasionally a many-to-many relationship needs to be established with an entity pointing to itself; In the case of the small domain we are working with, we can examine this with the concept of a Family - Person referencing Person.

public class Person
{
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public virtual ICollection<Person> Family { get; set; }
}

In this case, we are going to need mapping information as the default migration built for this makes each person belong to one, and only one family (we’re doing a learning exercise here, ok?)

public override void Up()
{
    AddColumn("dbo.People", "Person_PersonId", c => c.Int());
    CreateIndex("dbo.People", "Person_PersonId");
    AddForeignKey("dbo.People", "Person_PersonId", "dbo.People", "PersonId");
}

A mapping that you might think would work will cause an error The navigation property 'Family' declared on type 'LearnMappings.Person' cannot be the inverse of itself.

public PersonMap()
{
    HasMany(x => x.Family)
        .WithMany(x => x.Family);
}

In this case we need to leave WithMany empty. We also need to setup the Map information as the defaults will be kind of funky (PersonPerson with columns called Person_PersonId1 and Person_PersonId)

public class PersonMap : EntityTypeConfiguration<Person>
{
    public PersonMap()
    {
        HasMany(x => x.Family)
            .WithMany()
            .Map(x =>
            {
                x.ToTable("Family");
                x.MapLeftKey("PersonId");
                x.MapRightKey("OtherPersonId");
            });
    }
}

This gets us a migration that looks like this.

public override void Up()
{
    CreateTable(
        "dbo.PersonPersons",
        c => new
            {
                Person_PersonId = c.Int(nullable: false),
                Person_PersonId1 = c.Int(nullable: false),
            })
        .PrimaryKey(t => new { t.Person_PersonId, t.Person_PersonId1 })
        .ForeignKey("dbo.People", t => t.Person_PersonId)
        .ForeignKey("dbo.People", t => t.Person_PersonId1)
        .Index(t => t.Person_PersonId)
        .Index(t => t.Person_PersonId1);
    
}

Leave a Comment