I have two model 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; }
}
I want to rename Survey
to StudentSurvey
, so it will have StudentSurveyId
. I update the class name and the properties in the models accordingly and add a migration.
However, I get:
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'.
I think it is trying to drop the data and because it requires data in the column (cannot be null) I'm seeing that error. But I don't want to drop the data. How can I just rename it?
EF Core treats the entity class rename as deleting the old entity and adding a new entity, hence generates a migration to drop the original table and create a new one.
The workaround requires the following steps:
(1) Before renaming the entity, "rename" the table and the PK column by using either ToTable
and HasColumnName
fluent API or data annotations. Also do the same for FK columns referencing the entity.
For instance:
[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) Add new migration. It will correctly rename the table, PK column, FK columns and the associated constraints:
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) Remove the annotations / fluent configuration and do the actual class/property rename:
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; }
}
rename the corresponding DbSet
if any:
public DbSet<StudentSurvey> StudentSurveys { get; set; }
and you are done.
You can verify that by adding a new migration - it will have empty Up
and Down
methods.
The documentation suggests using MigrationBuilder.RenameColumn()
. There is also RenameIndex()
, RenameTable()
and a stored procedure 'sp_rename' (in SQL Server) for renaming foreign keys. E.g:
migrationBuilder.Sql($"EXEC sp_rename 'dbo.{oldName}', '{newName}'");
Use the database scripting tool in SQL Server Management Studio (rt-click on DB | Tasks | Generate Scripts...) to generate schema scripts, with and without EF migration customizations, that can be compared. Then you'll know the EF naming is preserved.
EDIT: Added 'EXEC ...' to support generation of standalone T-SQL scripts
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With