在不删除数据的情况下重命名 Entity Framework 核心中的外键
Rename a foreign key in Entity Framework Core without dropping data
我有两个模型 classes:
public class Survey
{
public int SurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int UserId { get; set; }
public int SurveyId { get; set; }
public Survey Survey { get; set; }
}
我想将 Survey
重命名为 StudentSurvey
,这样它就会有 StudentSurveyId
。我相应地更新了模型中的 class 名称和属性并添加了迁移。
但是,我得到:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_User_Surveys_SurveyId". The conflict occurred in database "AppName", table "dbo.Survey", column 'SurveyId'.
我认为它正在尝试删除数据,因为它需要列中的数据(不能为空),所以我看到了该错误。但我不想删除数据。我怎样才能重命名它?
EF Core 将实体 class 重命名视为删除旧实体并添加新实体,因此生成迁移以删除原始 table 并创建新实体。
解决方法需要执行以下步骤:
(1) 在重命名实体之前,"rename" table 和 PK 列使用 ToTable
和 HasColumnName
fluent API 或数据注释。也对引用实体的 FK 列执行相同的操作。
例如:
[Table("StudentSurveys")]
public class Survey
{
[Column("StudentSurveyId")]
public int SurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int UserId { get; set; }
[Column("StudentSurveyId")]
public int SurveyId { get; set; }
public Survey Survey { get; set; }
}
(2) 添加新迁移。它将正确重命名 table、PK 列、FK 列和关联的约束:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Surveys_SurveyId",
table: "Users");
migrationBuilder.DropPrimaryKey(
name: "PK_Surveys",
table: "Surveys");
migrationBuilder.RenameTable(
name: "Surveys",
newName: "StudentSurveys");
migrationBuilder.RenameColumn(
name: "SurveyId",
table: "Users",
newName: "StudentSurveyId");
migrationBuilder.RenameIndex(
name: "IX_Users_SurveyId",
table: "Users",
newName: "IX_Users_StudentSurveyId");
migrationBuilder.RenameColumn(
name: "SurveyId",
table: "StudentSurveys",
newName: "StudentSurveyId");
migrationBuilder.AddPrimaryKey(
name: "PK_StudentSurveys",
table: "StudentSurveys",
column: "StudentSurveyId");
migrationBuilder.AddForeignKey(
name: "FK_Users_StudentSurveys_StudentSurveyId",
table: "Users",
column: "StudentSurveyId",
principalTable: "StudentSurveys",
principalColumn: "StudentSurveyId",
onDelete: ReferentialAction.Cascade);
}
(3) 删除注释/流畅的配置并进行实际的 class/property 重命名:
public class StudentSurvey
{
public int StudentSurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int SurveyUserId { get; set; }
public int StudentSurveyId { get; set; }
public StudentSurvey StudentSurvey { get; set; }
}
重命名相应的 DbSet
如果有:
public DbSet<StudentSurvey> StudentSurveys { get; set; }
大功告成。
您可以通过添加新的迁移来验证这一点 - 它会有空的 Up
和 Down
方法。
documentation suggests using MigrationBuilder.RenameColumn()
. There is also RenameIndex()
, RenameTable()
and a stored procedure 'sp_rename'(在 SQL 服务器中)用于重命名外键。例如:
migrationBuilder.Sql($"EXEC sp_rename 'dbo.{oldName}', '{newName}'");
使用 SQL Server Management Studio 中的数据库脚本工具(rt-click on DB | Tasks | Generate Scripts...)生成模式脚本,有和没有 EF 迁移定制,可以进行比较。然后你就会知道 EF 命名被保留了。
编辑: 添加了 'EXEC ...' 以支持生成独立的 T-SQL 脚本
我有两个模型 classes:
public class Survey
{
public int SurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int UserId { get; set; }
public int SurveyId { get; set; }
public Survey Survey { get; set; }
}
我想将 Survey
重命名为 StudentSurvey
,这样它就会有 StudentSurveyId
。我相应地更新了模型中的 class 名称和属性并添加了迁移。
但是,我得到:
The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_User_Surveys_SurveyId". The conflict occurred in database "AppName", table "dbo.Survey", column 'SurveyId'.
我认为它正在尝试删除数据,因为它需要列中的数据(不能为空),所以我看到了该错误。但我不想删除数据。我怎样才能重命名它?
EF Core 将实体 class 重命名视为删除旧实体并添加新实体,因此生成迁移以删除原始 table 并创建新实体。
解决方法需要执行以下步骤:
(1) 在重命名实体之前,"rename" table 和 PK 列使用 ToTable
和 HasColumnName
fluent API 或数据注释。也对引用实体的 FK 列执行相同的操作。
例如:
[Table("StudentSurveys")]
public class Survey
{
[Column("StudentSurveyId")]
public int SurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int UserId { get; set; }
[Column("StudentSurveyId")]
public int SurveyId { get; set; }
public Survey Survey { get; set; }
}
(2) 添加新迁移。它将正确重命名 table、PK 列、FK 列和关联的约束:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Users_Surveys_SurveyId",
table: "Users");
migrationBuilder.DropPrimaryKey(
name: "PK_Surveys",
table: "Surveys");
migrationBuilder.RenameTable(
name: "Surveys",
newName: "StudentSurveys");
migrationBuilder.RenameColumn(
name: "SurveyId",
table: "Users",
newName: "StudentSurveyId");
migrationBuilder.RenameIndex(
name: "IX_Users_SurveyId",
table: "Users",
newName: "IX_Users_StudentSurveyId");
migrationBuilder.RenameColumn(
name: "SurveyId",
table: "StudentSurveys",
newName: "StudentSurveyId");
migrationBuilder.AddPrimaryKey(
name: "PK_StudentSurveys",
table: "StudentSurveys",
column: "StudentSurveyId");
migrationBuilder.AddForeignKey(
name: "FK_Users_StudentSurveys_StudentSurveyId",
table: "Users",
column: "StudentSurveyId",
principalTable: "StudentSurveys",
principalColumn: "StudentSurveyId",
onDelete: ReferentialAction.Cascade);
}
(3) 删除注释/流畅的配置并进行实际的 class/property 重命名:
public class StudentSurvey
{
public int StudentSurveyId { get; set; }
public string Name { get; set; }
}
public class User
{
public int SurveyUserId { get; set; }
public int StudentSurveyId { get; set; }
public StudentSurvey StudentSurvey { get; set; }
}
重命名相应的 DbSet
如果有:
public DbSet<StudentSurvey> StudentSurveys { get; set; }
大功告成。
您可以通过添加新的迁移来验证这一点 - 它会有空的 Up
和 Down
方法。
documentation suggests using MigrationBuilder.RenameColumn()
. There is also RenameIndex()
, RenameTable()
and a stored procedure 'sp_rename'(在 SQL 服务器中)用于重命名外键。例如:
migrationBuilder.Sql($"EXEC sp_rename 'dbo.{oldName}', '{newName}'");
使用 SQL Server Management Studio 中的数据库脚本工具(rt-click on DB | Tasks | Generate Scripts...)生成模式脚本,有和没有 EF 迁移定制,可以进行比较。然后你就会知道 EF 命名被保留了。
编辑: 添加了 'EXEC ...' 以支持生成独立的 T-SQL 脚本