在 Entity Framework Code First 中为同一个 table 定义多个外键
Defining multiple Foreign Key for the Same table in Entity Framework Code First
我的 MVC 应用程序中有两个实体,我使用 Entity Framework6 Code First 方法填充了数据库。 Student实体中有两个city id;其中一个用于 BirthCity,另一个用于 WorkingCity。当我如上所述定义外键时,迁移后会在 Student table 中创建一个名为 City_ID 的额外列。是否有错误或如何定义这些 FK?提前致谢。
学生:
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; }
}
城市:
public class City
{
public int ID { get; set; }
public string CityName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
嘘。这是漫长的一天。实际上,您的代码存在一个非常明显的大问题,实际上,我在评论时完全错过了。
问题是您在 City
上使用单个学生集合。这里实际发生的情况是 EF 无法决定它应该将该集合实际映射到哪个外键,因此它创建了另一个外键专门用于跟踪该关系。然后,实际上您没有从 BirthCity
和 LivingCity
.
派生的学生集合的导航属性
为此,您必须使用流畅的配置,因为无法仅使用数据注释来正确配置它。您还需要额外的学生集合,以便您可以跟踪这两种关系:
public class City
{
...
public virtual ICollection<Student> BirthCityStudents { get; set; }
public virtual ICollection<Student> LivingCityStudents { get; set; }
}
然后,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);
}
}
}
最后在您的上下文中:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new Student.StudentMapping());
}
要实现你想要的,你需要提供一些额外的 configuration.Code 第一个约定可以识别双向关系,但当有
两个 entities.You 之间的多个双向关系可以添加配置(使用 Data Annotations 或 Fluent API)来呈现这个
模型构建器的信息。使用数据注释,您将使用注释
称为 InverseProperty
。使用 Fluent API,您将使用 Has
/With
方法的组合来指定这些关系的正确端点。
使用数据注释可能是这样的:
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; }
}
通过这种方式,您可以明确指定要将 BirthCity
导航 属性 与关系另一端的 Students
导航 属性 相关联。
使用 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);
}
使用最后一个解决方案,您不需要使用任何属性。
现在,@ChristPratt 在您的 City
class 中为每个关系收集 Student
的建议非常有用。如果你这样做,那么使用 Data Annotations 的配置可能是这样的:
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; }
}
或使用 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);
}
我的 MVC 应用程序中有两个实体,我使用 Entity Framework6 Code First 方法填充了数据库。 Student实体中有两个city id;其中一个用于 BirthCity,另一个用于 WorkingCity。当我如上所述定义外键时,迁移后会在 Student table 中创建一个名为 City_ID 的额外列。是否有错误或如何定义这些 FK?提前致谢。
学生:
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; }
}
城市:
public class City
{
public int ID { get; set; }
public string CityName { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
嘘。这是漫长的一天。实际上,您的代码存在一个非常明显的大问题,实际上,我在评论时完全错过了。
问题是您在 City
上使用单个学生集合。这里实际发生的情况是 EF 无法决定它应该将该集合实际映射到哪个外键,因此它创建了另一个外键专门用于跟踪该关系。然后,实际上您没有从 BirthCity
和 LivingCity
.
为此,您必须使用流畅的配置,因为无法仅使用数据注释来正确配置它。您还需要额外的学生集合,以便您可以跟踪这两种关系:
public class City
{
...
public virtual ICollection<Student> BirthCityStudents { get; set; }
public virtual ICollection<Student> LivingCityStudents { get; set; }
}
然后,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);
}
}
}
最后在您的上下文中:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new Student.StudentMapping());
}
要实现你想要的,你需要提供一些额外的 configuration.Code 第一个约定可以识别双向关系,但当有
两个 entities.You 之间的多个双向关系可以添加配置(使用 Data Annotations 或 Fluent API)来呈现这个
模型构建器的信息。使用数据注释,您将使用注释
称为 InverseProperty
。使用 Fluent API,您将使用 Has
/With
方法的组合来指定这些关系的正确端点。
使用数据注释可能是这样的:
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; }
}
通过这种方式,您可以明确指定要将 BirthCity
导航 属性 与关系另一端的 Students
导航 属性 相关联。
使用 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);
}
使用最后一个解决方案,您不需要使用任何属性。
现在,@ChristPratt 在您的 City
class 中为每个关系收集 Student
的建议非常有用。如果你这样做,那么使用 Data Annotations 的配置可能是这样的:
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; }
}
或使用 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);
}