asp.net-mvc 在Entity Framework Code First中为同一个表定义多个外键
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28570916/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Defining multiple Foreign Key for the Same table in Entity Framework Code First
提问by Hyman
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.
我的 MVC 应用程序中有两个实体,我使用实体框架 6 代码优先方法填充了数据库。Student 实体中有两个城市 ID;其中一个用于 BirthCity,另一个用于 WorkingCity。当我在上面定义外键时,会在迁移后在 Student 表中创建一个名为 City_ID 的额外列。是否有错误或如何定义这些 FK?提前致谢。
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; }
}
回答by octavioccl
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 Annotationsor 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/Withmethods to specify the correct ends of these relationships.
为了实现你想要的,你需要提供一些额外的配置。Code First 约定可以识别双向关系,但当两个实体之间存在多个双向关系时不能。你可以添加配置(使用数据注释或Fluent API)来呈现此信息到模型构建器。对于数据注释,您将使用一个名为InverseProperty. 使用 Fluent API,您将使用Has/With方法的组合来指定这些关系的正确端。
Using Data Annotationscould 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 BirthCitynavigation property with Studentsnavigation property in the other end of the relationship.
通过这种方式,您明确指定要将BirthCity导航属性与Students关系另一端的导航属性相关联。
Using Fluent Apicould be like this:
使用Fluent Api可能是这样的:
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 Studentin your Cityclass for each relationship is really useful. If you do that, then the configurations using Data Annotationscould be this way:
现在,@ChristPratt 的建议Student在你的City课堂上为每个关系收集一个集合真的很有用。如果你这样做,那么使用数据注释的配置可能是这样的:
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 Apifollowing the same idea:
或者按照相同的想法使用Fluent Api:
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);
}
回答by Chris Pratt
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 BirthCityand LivingCity.
问题是您在City. 这里实际发生的是 EF 无法决定它应该将该集合实际映射到哪个外键,因此它创建了另一个专门用于跟踪该关系的外键。然后,实际上您没有从BirthCity和派生的学生集合的导航属性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:
然后,对于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());
}

