【问题标题】:ForeignKey to the same table with custom column name具有自定义列名的同一个表的 ForeignKey
【发布时间】:2018-11-24 07:01:46
【问题描述】:

我有一个模特User

public class User
{
    [Key]
    public int IDUser { get; set; }
    [Required]
    public string Forename { get; set; }
    [Required]
    public string Name { get; set; }                          

    public int? IDUser_CreatedBy { get; set; }
    public User User_CreatedBy { get; set; }
}

用户可以拥有其创建者 (User_CreatedBy) 及其 ID (IDUser_CreatedBy),当然它驻留在同一张表中,但我希望有机会将其保留为空值 (User,创建者未知) .这就是为什么 IDUser_CreatedByint? 可以为空的类型。

我不知道如何设置我的 fluent API,以便将外键 IDUser_CreatedBy 绑定到同一张表中的主键 IDUser

我知道,如果我从该模型中删除 IDUser_CreatedBy 外键并添加新迁移,那么 EF 核心将为我隐含地生成影子属性外键,但我希望稍后有机会更新我的 User(在 MVC 中控制器)具有自定义创建的列IDUser_CreatedBy,并且能够为自己命名该列。此外,我不想要那个影子属性,因为我无法控制该列的命名。

我怎样才能做到这一点?

编辑

@IvanStoev - 感谢您的回答,但您的示例没有为我生成有效的迁移代码:

protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Users_Users_CreatedByIDUser",
            table: "Users");

        migrationBuilder.RenameColumn(
            name: "CreatedByIDUser",
            table: "Users",
            newName: "UserIDUser");

        migrationBuilder.RenameIndex(
            name: "IX_Users_CreatedByIDUser",
            table: "Users",
            newName: "IX_Users_UserIDUser");

        migrationBuilder.AddColumn<int>(
            name: "IDUser_CreatedBy",
            table: "Users",
            nullable: true);

        migrationBuilder.CreateIndex(
            name: "IX_Users_IDUser_CreatedBy",
            table: "Users",
            column: "IDUser_CreatedBy");

        migrationBuilder.AddForeignKey(
            name: "FK_Users_Users_IDUser_CreatedBy",
            table: "Users",
            column: "IDUser_CreatedBy",
            principalTable: "Users",
            principalColumn: "IDUser",
            onDelete: ReferentialAction.Restrict);

        migrationBuilder.AddForeignKey(
            name: "FK_Users_Users_UserIDUser",
            table: "Users",
            column: "UserIDUser",
            principalTable: "Users",
            principalColumn: "IDUser",
            onDelete: ReferentialAction.Restrict);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Users_Users_IDUser_CreatedBy",
            table: "Users");

        migrationBuilder.DropForeignKey(
            name: "FK_Users_Users_UserIDUser",
            table: "Users");

        migrationBuilder.DropIndex(
            name: "IX_Users_IDUser_CreatedBy",
            table: "Users");

        migrationBuilder.DropColumn(
            name: "IDUser_CreatedBy",
            table: "Users");

        migrationBuilder.RenameColumn(
            name: "UserIDUser",
            table: "Users",
            newName: "CreatedByIDUser");

        migrationBuilder.RenameIndex(
            name: "IX_Users_UserIDUser",
            table: "Users",
            newName: "IX_Users_CreatedByIDUser");

        migrationBuilder.AddForeignKey(
            name: "FK_Users_Users_CreatedByIDUser",
            table: "Users",
            column: "CreatedByIDUser",
            principalTable: "Users",
            principalColumn: "IDUser",
            onDelete: ReferentialAction.Restrict);
    }

它确实生成了我想要的 ForeignKey 列 (IDUser_CreatedBy) 和该键列的有效索引 (IX_Users_IDUser_CreatedBy) 但它还添加了另一个 ForeignKey (UserIDUser) 女巫是我猜的影子属性。因此,我有 2 个不同的 ForeignKey 列,它们引用同一个表中的一个 Primerykey 列 (IDUser)。在我的例子中,迁移实际上将旧列 (CreatedByIDUser) 重命名为新列 (UserIDUser),这是我之前的影子属性 ForeignKey 列的残余。我正在寻找的是迁移将完全摆脱以前的影子属性并只引入一个新的 ForeignKey 列 (IDUser_CreatedBy)。有什么建议 ?

编辑 2

@viveknuna - 谢谢你的例子,但它也不适合我。

迁移看起来像这样:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Users_Users_CreatedByIDUser",
            table: "Users");

        migrationBuilder.RenameColumn(
            name: "CreatedByIDUser",
            table: "Users",
            newName: "User_CreatedByIDUser");

        migrationBuilder.RenameIndex(
            name: "IX_Users_CreatedByIDUser",
            table: "Users",
            newName: "IX_Users_User_CreatedByIDUser");

        migrationBuilder.AddColumn<int>(
            name: "IDUser_CreatedBy",
            table: "Users",
            nullable: true);

        migrationBuilder.AddForeignKey(
            name: "FK_Users_Users_User_CreatedByIDUser",
            table: "Users",
            column: "User_CreatedByIDUser",
            principalTable: "Users",
            principalColumn: "IDUser",
            onDelete: ReferentialAction.Restrict);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropForeignKey(
            name: "FK_Users_Users_User_CreatedByIDUser",
            table: "Users");

        migrationBuilder.DropColumn(
            name: "IDUser_CreatedBy",
            table: "Users");

        migrationBuilder.RenameColumn(
            name: "User_CreatedByIDUser",
            table: "Users",
            newName: "CreatedByIDUser");

        migrationBuilder.RenameIndex(
            name: "IX_Users_User_CreatedByIDUser",
            table: "Users",
            newName: "IX_Users_CreatedByIDUser");

        migrationBuilder.AddForeignKey(
            name: "FK_Users_Users_CreatedByIDUser",
            table: "Users",
            column: "CreatedByIDUser",
            principalTable: "Users",
            principalColumn: "IDUser",
            onDelete: ReferentialAction.Restrict);
    }

它将我的剩余影子属性 ForeignKey 重命名为新名称,但它保留了该影子属性。迁移还添加了不是 ForeignKey 的新列 IDUser_CreatedBy(该列没有 AddForeignKeyCreateIndex 方法)。

编辑 3

@Ivan Stoev - 你是对的。我没有提交整个模型,因为我认为它不会对结果产生影响,但现在很明显它有...... :) 首先 - 我确实创建了一个全新的命令行项目并设法将正确的迁移作为你说。然后我意识到我的模型还有另一个属性public List&lt;User&gt; UsersAdded { get; set; },它描述了由该特定User 添加的所有用户。这就是罪魁祸首。它将新列 UserIDUser 添加到新创建的迁移中。所以最后一个问题是:我怎样才能通过新属性public List&lt;User&gt; UsersAdded { get; set; } 实现我所需要的一切?因为我想有机会在我的 MVC 控制器中包含 User 在获得 User 时创建的 User 集合。作为一种形式,我提交了我的整个模型(这次是正确的):

public class User
{
    [Key]
    public int IDUser { get; set; }
    [Required]
    public string Forename { get; set; }
    [Required]
    public string Name { get; set; }
    public string AvatarPath { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string Password { get; set; }
    public bool IsWebUser { get; set; }
    public DateTimeOffset CreatedAt { get; set; }

    public int? IDUser_CreatedBy { get; set; }
    public User User_CreatedBy { get; set; }

    public List<User> UsersAdded { get; set; }
}

【问题讨论】:

  • 显然您的代码中还有其他内容未在此处显示。 EF 迁移无法使用此模型和建议的流畅配置创建列“UserIDUser”。仅使用您的帖子和我的回答中的代码创建一个干净的新项目,您会看到迁移将生成正确的CreateTable

标签: c# entity-framework-core ef-fluent-api ef-core-2.0


【解决方案1】:

EF Core fluent API 让您可以完全控制命名表列,无论您是使用显式模型属性还是影子模型属性。非常规外键属性使用 relationship 配置的 HasForeignKey fluent API 进行映射。

您的实体模型属于具有显式 FK 属性类别的 Single Navigation Property,可以像这样映射:

modelBuilder.Entity<User>()
    .HasOne(e => e.User_CreatedBy) // reference navigation property
    .WithMany() // no collection navigation property
    .HasForeignKey(e => e.IDUser_CreatedBy); // foreign key property

【讨论】:

    【解决方案2】:

    添加到@Ivan 答案,您还可以通过在类中使用[Column("NewColumnName")] 属性来更改列名。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-13
      • 1970-01-01
      • 2015-11-23
      • 2021-04-30
      • 2021-03-22
      • 2012-04-27
      相关资源
      最近更新 更多