在 EF Core 中添加外键列

Add Foreign Key Column In EF Core

我有一个现有的 table Projects,我想向其中添加一个 UserId 列,其中 UserId 是一个外键。 Projects 现在有一个名称列表,但我希望每个用户都能管理自己的项目。我可以接受 "orphans" 一开始,因为列表足够小,我可以手动清理它们。

我更新了我的模型以包含 UserId 和导航 属性 User(可能不相关,但 Entity 这里是基础 class IdDateModified)

public class Project : Entity
{
    public string Name { get; set; }
    public Guid? UserId { get; set; } //tried this as nullable and non nullable
    public User User { get; set; }
}

而我的相关映射文件是

public class ProjectMap : IEntityTypeConfiguration<Project>
{
    public void Configure(EntityTypeBuilder<Project> builder)
    {
        builder.Property(x => x.Name).IsRequired();
        builder.Property(x => x.UserId).IsRequired();

        builder.HasOne(x => x.User)
            .WithMany(x => x.Projects)
            .HasForeignKey(x => x.UserId)
            .OnDelete(DeleteBehavior.SetNull);  //I have tried numerous combinations of things here....
    }
}

我还向项目的 User 实体添加了导航 属性,但未对映射 class.

进行任何更改
public class User : Entity
{
    public string EmailAddress { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Task> Tasks { get; set; }
    public List<Project> Projects { get; set; }
}

由此生成的迁移:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<Guid>(
            name: "UserId",
            table: "Projects",
            nullable: false,
            defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));

        migrationBuilder.CreateIndex(
            name: "IX_Projects_UserId",
            table: "Projects",
            column: "UserId");

        migrationBuilder.AddForeignKey(
            name: "FK_Projects_Users_UserId",
            table: "Projects",
            column: "UserId",
            principalTable: "Users",
            principalColumn: "Id",
            onDelete: ReferentialAction.SetNull);
    }

当 运行 update-database

时转换为 SQL
ALTER TABLE [Projects] ADD CONSTRAINT [FK_Projects_Users_UserId] FOREIGN KEY ([UserId]) REFERENCES [Users] ([Id]) ON DELETE SET NULL;

并因此错误而失败

Cannot create the foreign key "FK_Projects_Users_UserId" with the SET NULL referential action, because one or more referencing columns are not nullable.

我做错了什么?

以下行导致了问题,因为您想要 Project

上的可为空 FK
builder.Property(x => x.UserId).IsRequired();

另外,您生成的迁移已经有提示:

 nullable: false,

只需删除您的 Configure 方法中的那一行,它就会起作用。您可能还需要通过 运行 Remove-Migration 删除迁移,然后再次 运行 添加迁移。这次你应该有这个:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AlterColumn<string>(
        name: "Name",
        table: "Projects",
        nullable: false,
        oldClrType: typeof(string),
        oldNullable: true);

    migrationBuilder.AddColumn<Guid>(
        name: "UserId",
        table: "Projects",
        nullable: true);

    migrationBuilder.CreateIndex(
        name: "IX_Projects_UserId",
        table: "Projects",
        column: "UserId");

    migrationBuilder.AddForeignKey(
        name: "FK_Projects_Users_UserId",
        table: "Projects",
        column: "UserId",
        principalTable: "Users",
        principalColumn: "Id",
        onDelete: ReferentialAction.SetNull);
}

如果需要,您可以在配置关系时通过显式设置 IsRequired 来更具体:

private static void ConfigureProject(EntityTypeBuilder<Project> b)
{
    b.Property(x => x.Name).IsRequired();

    b.HasOne(x => x.User)
        .WithMany(x => x.Projects)
        .HasForeignKey(x => x.UserId)
        .IsRequired(false)
        .OnDelete(DeleteBehavior.SetNull);
}

我喜欢这个,尽管 属性 已经可以为 null,并且 EF 将使用它的约定来正确创建它,但对于阅读配置并了解它而无需转到实际项目的人来说仍然很好class.

在函数配置中指定:

builder.Property(x => x.UserId).IsRequired();

这不是说UserId不能为null吗?但您希望它为空?