Defining multiple Foreign Key for the Same table in Entity Framework Code First

后端 未结 2 1292
陌清茗
陌清茗 2020-11-28 04:18

I have two entities in my MVC application and I populated the database with Entity Framework 6 Code First approach. There are two city id in the Student entity; one of them

相关标签:
2条回答
  • 2020-11-28 04:23

    To achieve what you want you need to provide some aditional configuration.Code First convention can identify bidirectional relationships, but not when there are multiple bidirectional relationships between two entities.You can add configuration (using Data Annotations or the Fluent API) to present this information to the model builder. With Data Annotations, you’ll use an annotation called InverseProperty. With the Fluent API, you’ll use a combination of the Has/With methods to specify the correct ends of these relationships.

    Using Data Annotations could be like this:

    public class Student
    {
      public int ID { get; set; }
    
      public string Name { get; set; }
    
      public string Surname { get; set; }
    
      public int BirthCityID { get; set; }
    
      public int LivingCityID { get; set; }
    
    
      [ForeignKey("BirthCityID")]
      [InverseProperty("Students")]
      public virtual City BirthCity { get; set; }
    
      [ForeignKey("LivingCityID")]
      public virtual City LivingCity { get; set; }
    }
    

    This way you specifying explicitly that you want to relate the BirthCity navigation property with Students navigation property in the other end of the relationship.

    Using Fluent Api could be like this:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity)
                                     .WithMany(m => m.Students).HasForeignKey(m=>m.BirthCityId);
         modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity)
                                     .WithMany().HasForeignKey(m=>m.LivingCityId);
    }
    

    With this last solution you don't need to use any attibute.

    Now, the suggestion of @ChristPratt in have a collection of Student in your City class for each relationship is really useful. If you do that, then the configurations using Data Annotations could be this way:

    public class Student
    {
      public int ID { get; set; }
    
      public string Name { get; set; }
    
      public string Surname { get; set; }
    
      public int BirthCityID { get; set; }
    
      public int LivingCityID { get; set; }
    
    
      [ForeignKey("BirthCityID")]
      [InverseProperty("BirthCityStudents")]
      public virtual City BirthCity { get; set; }
    
      [ForeignKey("LivingCityID")]
      [InverseProperty("LivingCityStudents")]
      public virtual City LivingCity { get; set; }
    }
    

    Or using Fluent Api following the same idea:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Student>().HasRequired(m => m.BirthCity)
                   .WithMany(m => m.BirthCityStudents).HasForeignKey(m=>m.BirthCityId);
         modelBuilder.Entity<Student>().HasRequired(m => m.LivingCity)
                   .WithMany(m => m.LivingCityStudents).HasForeignKey(m=>m.LivingCityId);
    }
    
    0 讨论(0)
  • 2020-11-28 04:30

    Sheesh. It's been a long day. There's actually a very big, glaring problem with your code, actually, that I completely missed when I commented.

    The problem is that you're using a single collection of students on City. What's actually happening here is that EF can't decide which foreign key it should actually map that collection to, so it creates another foreign key specifically to track that relationship. Then, in effect you have no navigation properties for the collections of students derived from BirthCity and LivingCity.

    For this, you have to drop down to fluent configuration, as there's no way to configure this properly using just data annotations. You'll also need an additional collection of students so you can track both relationships:

    public class City
    {
        ...
    
        public virtual ICollection<Student> BirthCityStudents { get; set; }
        public virtual ICollection<Student> LivingCityStudents { get; set; }
    }
    

    Then, for Student:

    public class Student
    {
        ...
    
        public class StudentMapping : EntityTypeConfiguration<Student>
        {
            public StudentMapping()
            {
                HasRequired(m => m.BirthCity).WithMany(m => m.BirthCityStudents);
                HasRequired(m => m.LivingCity).WithMany(m => m.LivingCityStudents);
            }
        }
    }
    

    And finally in your context:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new Student.StudentMapping());
    }
    
    0 讨论(0)
提交回复
热议问题