Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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 for BirthCity, the other for WorkingCity. When I define the foreign keys as above an extra column is created named City_ID in the Student table after migration. Id there a mistake or how to define these FKs? Thanks in advance.

Student:

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")]     public virtual City BirthCity { get; set; }      [ForeignKey("LivingCityID")]     public virtual City LivingCity { get; set; } } 


City:

public class City {     public int ID { get; set; }      public string CityName { get; set; }       public virtual ICollection<Student> Students { get; set; } } 
like image 733
Jack Avatar asked Feb 17 '15 20:02

Jack


People also ask

Can a table have multiple foreign keys from same table?

A table can have multiple foreign keys based on the requirement.

Can an entity have multiple foreign keys?

A table may have multiple foreign keys, and each foreign key can have a different parent table. Each foreign key is enforced independently by the database system. Therefore, cascading relationships between tables can be established using foreign keys.

Can two foreign keys in the same table reference the same primary key?

Yes, it is okay to have two fk to the same pk in one table.

Can a table have more than one foreign key defined?

The FOREIGN KEY constraint differs from the PRIMARY KEY constraint in that, you can create only one PRIMARY KEY per each table, with the ability to create multiple FOREIGN KEY constraints in each table by referencing multiple parent table.


1 Answers

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); } 
like image 55
octavioccl Avatar answered Sep 24 '22 12:09

octavioccl