在 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 无法决定它应该将该集合实际映射到哪个外键,因此它创建了另一个外键专门用于跟踪该关系。然后,实际上您没有从 BirthCityLivingCity.

派生的学生集合的导航属性

为此,您必须使用流畅的配置,因为无法仅使用数据注释来正确配置它。您还需要额外的学生集合,以便您可以跟踪这两种关系:

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 AnnotationsFluent 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);
}