web-dev-qa-db-ja.com

EFコアに外部キー列を追加する

Projects列を追加したい既存のテーブルUserIdがあります。ここで、UserIdは外部キーです。 Projectsには現在名前のリストがありますが、各ユーザーが自分のプロジェクトを管理できるようにしたいと思います。リストは十分に小さいので、手動でクリーンアップできるので、最初は「孤立」があっても問題ありません。

モデルを更新して、UserIdとナビゲーションプロパティUserを含めました(おそらく関係ありませんが、EntityIdDateModified

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エンティティにナビゲーションプロパティも追加しましたが、マッピングクラスに変更を加えていません。

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.

私は何が間違っているのですか?

4
Joe

Projectにnull許容FKが必要なため、以下の行が問題の原因です。

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

また、生成された移行には、すでにヒントがあります。

 nullable: false,

Configureメソッドでその行を削除するだけで、機能するはずです。 Remove-Migrationを実行してから、add-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はその規則を使用して正しく作成しますが、実際のP​​rojectクラスに移動しなくても、構成を読んでそれを知っている人にとっては便利です。

9
jpgrassi

機能構成で、以下を指定します。

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

それは、UserIdがnullではない可能性があることを意味しませんか?それでも、nullにしたいですか?

1