当前位置: 首页 > 知识库问答 >
问题:

首先在实体框架代码中为同一个表定义多个外键

梁丘缪文
2023-03-14

我的MVC应用程序中有两个实体,我使用实体框架6代码优先的方法填充数据库。学生实体中有两个城市id;其中一个代表出生城市,另一个代表工作城市。当我如上所述定义外键时,将在迁移后在学生表中创建一个名为City\u 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; }
}

共有2个答案

范瀚昂
2023-03-14

嘘。这是漫长的一天。实际上,您的代码有一个非常大的、明显的问题,实际上,我在评论时完全没有注意到。

问题是,您使用的是城市上的单个学生集合。这里实际发生的是,EF无法决定它应该将集合映射到哪个外键,因此它会创建另一个外键来专门跟踪该关系。然后,实际上,对于从出生城市和生活城市派生的学生集合,您没有导航属性。

为此,您必须下拉到fluent配置,因为仅使用数据注释无法正确配置。您还需要一个额外的学生集合,以便跟踪这两种关系:

public class City
{
    ...

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

然后,对于学生:

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());
}
司空海荣
2023-03-14

为了实现您想要的,您需要提供一些传统的配置。代码优先约定可以识别双向关系,但当两个实体之间存在多个双向关系时,则不能识别。您可以添加配置(使用数据注释或Fluent API)以将此信息呈现给模型生成器。对于数据注释,您将使用名为InverseProperty的注释。使用Fluent API,您将使用Has方法与code方法的组合来指定这些关系的正确endpoint。

使用数据注释可能如下所示:

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

这样,您可以明确指定要将出生地导航属性与关系另一端的学生导航属性相关联。

使用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);
}

对于最后一个解决方案,您不需要使用任何attibute。

现在,@ChristPratt在你所在城市的班级中收集学生,对于每种关系都非常有用。如果这样做,那么使用数据注释的配置可能是这样的:

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);
}
 类似资料:
  • 问题内容: 我首先在我的项目中使用EF代码。我的DataModel中有以下代码 为了使该值不为空,我删除了“?” 并从“程序包管理器”控制台中运行“添加迁移”命令。以下迁移文件已生成。 但是当我运行Update-Database命令时: 我收到以下错误:无法将值NULL插入表“’‘的“ PasswordDate”列中;列不允许为空。UPDATE失败。该语句已终止。 请提出解决方案。 问题答案: 那

  • 在实体框架中,我想使用两个外键作为另一个实体类型的主键。 但是,这会给我一个缺少键的错误。 我知道我可以定义另外两个属性来保存引用实体类型的主键。Visual Studio是否不够聪明,无法自行使用它们的主键?

  • 我正在使用实体框架管理我的sql server ce数据库。我希望我的表的主键由其他表的几个外键组成。我希望这样的事情能奏效: 但它会导致以下数据库迁移错误: 票据打印机。Bill::EntityType“Bill”没有定义键。定义此EntityType的键。Bills:EntityType:EntitySet“Bills”基于未定义键的类型“Bill”。 如何使表具有由这三个外键组成的主键?

  • 问题内容: 我想建立这样的关系(一个区域在x个其他区域的附近) 不幸的是,这是行不通的,因为EF生成的FK不正确…我如何才能使像这样的结构起作用? 3个区域的示例:3 Zones: Zone 1, Zone 2, Zone 3 Zone 1 Neighours: Zone 2, Zone 3 Zone 2 Neighbours: Zone 1 Zone 3 Neighbours: Zone1 有什

  • 因此,我使用实体框架的“代码优先”方法,并且我有映射文件来映射表信息并添加诸如验证之类的内容,例如: 这是在使用Fluent API,我想知道如何通过字符串而不是T.AccountName获得属性名。我想动态设置这些属性,但我不知道如何通过编程实现。

  • [将代码优先DbContext与实体框架5.0 RC一起使用] DbUpdateException:更新条目时出错 我需要能够将这些父类保存到数据库中,因为它们是唯一的,即使它们有时包含已存储的导航属性-我如何从这个子主键冲突中保存父类?