具有不同列名的 EF Core 5 HasForeignKey 问题

Posted

技术标签:

【中文标题】具有不同列名的 EF Core 5 HasForeignKey 问题【英文标题】:EF Core 5 HasForeignKey Problem with Differing Column Name 【发布时间】:2021-10-10 20:48:11 【问题描述】:

环境:.Net 5.0、EntityFrameworkCore 5.0、MS Sql Server

我已经在我的数据库中设置了一对多关系(使用HasForeignKey),但是当我尝试使用.Include(x => x.Parent) 从子级访问父记录时,我得到一个无效的列名错误。我过去做过很多次这种类型的事情,但总是Child 表有一个名为ParentTableName + Id 的属性(以及所述属性上的FK)。在这种失败的情况下,属性与该模式不匹配。

所以我的问题是:为什么 EF 会忽略我的 Fluent API 配置?在我看来,如果我正确设置了关系(并且每列上的数据类型匹配),那么该列被称为什么并不重要。在流畅的 api 设置中我需要采取一些额外的步骤吗?请参见下面的示例:

public class Parent

    public int Id  get; set; 
    public IEnumerable<Child> Children  get; set; 


public class Child 

    public int Id  get; set; 
    public int ForeignKeyName  get; set;  // This could say anything, just not "ParentId"
    
    [NotMapped] // Included so add-migration doesn't try to create a mapping, but when removed I get the same error
    public Parent Parent  get; set; 

还有我的配置

modelBuilder.Entity<Parent>(entity =>

    entity.HasMany<Child>()
    .WithOne(x => x.Parent)
    .HasForeignKey(x => x.ForeignKeyName);
);

失败的用法:

var children = _context.Children.Include(x => x.Parent).ToList(); // Says "Invalid Column Name 'ParentId'"

外键已在数据库中设置,但当我尝试运行 add-migration 时,它仍然建议创建 a) 在 Child 上创建一个名为 ParentId 的新列(为什么?),b) 在所述列,以及 c) 使用ParentId 的外键。我宁愿了解这里发生了什么,也不愿只是更改属性名称并保持幸福的无知。

编辑 由于评论线程很长,因此更新以明确答案。关键是要确保 [NotMapped] 在两个导航属性上,并且(在下面的回答中)让流式 API 引用两个方向(父到子和子到父)的关系。

【问题讨论】:

【参考方案1】:

此代码在 VS 2019 中测试,成功创建 ForeignKeyName ForeignKey 的数据库。

你必须修复类

public class Parent

   [Key]
    public int Id  get; set; 
    [InverseProperty(nameof(Child.Parent))]
    public IEnumerable<Child> Children  get; set; 


public class Child 

    [Key]
    public int Id  get; set; 

    public int ForeignKeyName  get; set;  

    [ForeignKey(nameof(ForeignKeyName))]
    [InverseProperty("Children")]
    public Parent Parent  get; set; 

或数据库上下文

          modelBuilder.Entity<Child>(entity =>
            
                entity.HasOne(d => d.Parent)
                   .WithMany(p => p.Children)
                   .HasForeignKey(d => d.ForeignKeyName);
            );

您必须删除以前的 Migrations 文件夹并删除以前的数据库。在此之后使用 Add-Migration InitialCreate 进行清晰的迁移。然后使用更新数据库。

【讨论】:

这些对我不起作用。第一个代码块中的更改没有任何效果(Include 调用上的错误消息相同);添加第二个更改(我之前尝试过并希望修复它)会导致错误“无效的列名 ParentId1”;请注意名称中的 1,EF 有时会尝试添加阴影属性。当它被告知要使用什么属性作为键时,不知道为什么它想要一个影子属性。 @broccoli_rob 您必须删除所有旧数据库迁移文件夹和旧数据库。在此之后进行新的迁移,这将在尝试进行新查询之前创建一个新的数据库 似乎是一个核选项,但即使这样做,新的迁移文件也有这一行:migrationBuilder.RenameColumn(name: "ForeignKeyName", table: "Child", newName: ParentId1");,并且当第一次构建表时,它会尝试创建列“ParentId1” ,表示同样的问题。 @broccoli_rob 我刚刚在 VS 2019 中测试了我的代码。成功创建了带有 ForeignKeyName ForeignKey 的数据库。 是的,我得到了正确的 FK,但也得到了新列 ParentId,以及该属性上的 FK,这似乎是 EF 在运行 Include 时想要使用的。请问您使用的是哪个版本的 EF Core? migrationBuilder.CreateTable(name: "Child", columns: table =&gt; new ForeignKeyName = table.Column&lt;int&gt;(type: "int", nullable: false), ParentId = table.Column&lt;int&gt;(type: "int", nullable: true) // this shouldn't exist ,

以上是关于具有不同列名的 EF Core 5 HasForeignKey 问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 EF Core 过滤包含时的列名无效

EF Core,禁用外键列名生成

ef core 如何一次从具有外键的不同表中获取数据? (数据库优先)

EF Core从TPH迁移到TPT

使用流利的 api EF Core 5 的多对多关系

Laravel 5.5 对具有不同列名的单独表的唯一验证规则