Search code examples
entity-frameworkmany-to-manyprimary-key

Many-to-many relationship on the same table using a junction table and a primary key in EF


I have the following tables:

  • Sub_Option: Sub_Option_ID as PK, Name

  • Sub_Option_To_Sub_Option: Sub_Option_To_Sub_Option_ID as PK, Sub_Option_ID_Primary, Sub_Option_ID_Secondary

I would like to be able to access all the secondary sub options associated with the primary sub option via EF and vice-versa. Directly using .Map won't work as the junction table Sub_Option_To_Sub_Option has a primary key.

public class Sub_Option
{
    public int Sub_Option_ID { get; set; }
    public string Name { get; set; }
}

corresponding to Table

CREATE TABLE Sub_Option(
Sub_Option_ID int,
Name varchar(255)
);

and Table

CREATE TABLE Sub_Option_To_Sub_Option(
Sub_Option_To_Sub_Option int PK, 
Sub_Option_ID_Primary int,
Sub_Option_ID_Secondary int
);

Solution

  • This should work i think:

        public class OptionToOption
    {
        [Key]
        public int ID { get; set; }
    
        [ForeignKey("PrimaryOption")]
        public int PrimaryID { get; set; }
    
        [ForeignKey("SecondaryOption")]
        public int SecondaryID { get; set; }
    
        public virtual Option PrimaryOption { get; set; }
    
        public virtual Option SecondaryOption { get; set; }
    }
    
        public class Option
    {
        public Option()
        {
            OptionToOption = new HashSet<OptionToOption>();
        }
    
        [Key]
        public int ID { get; set; }
    
        public string Name { get; set; }
    
        public virtual ICollection<OptionToOption> OptionToOption { get; set; }
    }
    

    And in fluent api map like this (don't even think it's necessary to do this though):

                modelBuilder.Entity<Option>()
                .HasMany(e => e.OptionToOption)
                .WithRequired(e => e.PrimaryOption)
                .HasForeignKey(e => e.PrimaryID);
    
            modelBuilder.Entity<Option>()
                .HasMany(e => e.OptionToOption)
                .WithRequired(e => e.SecondaryOption)
                .HasForeignKey(e => e.SecondaryID);