Projects
列を追加したい既存のテーブルUserId
があります。ここで、UserId
は外部キーです。 Projects
には現在名前のリストがありますが、各ユーザーが自分のプロジェクトを管理できるようにしたいと思います。リストは十分に小さいので、手動でクリーンアップできるので、最初は「孤立」があっても問題ありません。
モデルを更新して、UserId
とナビゲーションプロパティUser
を含めました(おそらく関係ありませんが、Entity
はId
とDateModified
)
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.
私は何が間違っているのですか?
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はその規則を使用して正しく作成しますが、実際のProjectクラスに移動しなくても、構成を読んでそれを知っている人にとっては便利です。
機能構成で、以下を指定します。
builder.Property(x => x.UserId).IsRequired();
それは、UserIdがnullではない可能性があることを意味しませんか?それでも、nullにしたいですか?