在 EF Core 中添加外键列
Add Foreign Key Column In EF Core
我有一个现有的 table Projects
,我想向其中添加一个 UserId
列,其中 UserId
是一个外键。 Projects
现在有一个名称列表,但我希望每个用户都能管理自己的项目。我可以接受 "orphans" 一开始,因为列表足够小,我可以手动清理它们。
我更新了我的模型以包含 UserId
和导航 属性 User
(可能不相关,但 Entity
这里是基础 class 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
实体添加了导航 属性,但未对映射 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吗?但您希望它为空?
我有一个现有的 table Projects
,我想向其中添加一个 UserId
列,其中 UserId
是一个外键。 Projects
现在有一个名称列表,但我希望每个用户都能管理自己的项目。我可以接受 "orphans" 一开始,因为列表足够小,我可以手动清理它们。
我更新了我的模型以包含 UserId
和导航 属性 User
(可能不相关,但 Entity
这里是基础 class 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
实体添加了导航 属性,但未对映射 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
时转换为 SQLALTER 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
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吗?但您希望它为空?