【问题标题】:Rename a foreign key in Entity Framework Core without dropping data在 Entity Framework Core 中重命名外键而不删除数据
【发布时间】:2018-09-22 18:55:06
【问题描述】:

我有两个模型类:

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。我相应地更新模型中的类名和属性并添加迁移。

但是,我得到:

ALTER TABLE 语句与 FOREIGN KEY 约束“FK_User_Surveys_SurveyId”冲突。数据库“AppName”、表“dbo.Survey”、“SurveyId”列中发生冲突。

我认为它正在尝试删除数据,并且因为它需要列中的数据(不能为空),所以我看到了该错误。但我不想丢弃数据。我怎样才能重命名它?

【问题讨论】:

    标签: c# sql-server entity-framework entity-framework-core ef-core-2.0


    【解决方案1】:

    EF Core 将实体类重命名视为删除旧实体并添加新实体,因此会生成迁移以删除原始表并创建新表。

    解决方法需要以下步骤:

    (1) 在重命名实体之前,使用ToTableHasColumnName fluent API 或数据注释“重命名”表和PK 列。也对引用实体的 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) 添加新的迁移。它将正确地重命名表、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) 移除注解/流利的配置并做实际的类/属性重命名:

    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; }
    

    你就完成了。

    您可以通过添加新迁移来验证这一点 - 它将有空的 UpDown 方法。

    【讨论】:

    • 好像我需要在每个具有SurveyId 外键的模型上方添加[Column("StudentSurveyId")]。我会尝试...
    • 那行得通。然后我应用重命名重构 (resharper) 以在我的项目中将调查更改为 StudentSurvey。然后你的第 3 步没用;我的迁移代码中显示了 drop 和 create 语句。我忘了改变我的上下文:public DbSet&lt;StudentSurvey&gt; Surveys { get; set; } 需要变成public DbSet&lt;StudentSurvey&gt; StudentSurveys { get; set; } 然后我遇到了同样的问题。因为 StudentSurveys 必须是 StudentSurvey。事后看来,我应该在我的第一个注释中将[Table(StudentSurvey)] 复数化。我建议更新您的答案以考虑所有这些。
    • 好的。至少这是一个很好的起点 :) 在我的测试中,我没有重命名 FK 列。并假设DbSet 重命名是“重命名”操作的一部分。反正现在答案更新了,是不是漏了什么?
    • @PateeGutee 不幸的是,这似乎不适用于 EF6。
    • 在 EF 核心 3 中:如果我不生成第二次(空)迁移,那么我仍然在 ModelSnapshot 中:b.Property("Old") .HasColumnName("New")跨度>
    【解决方案2】:

    documentation 建议使用MigrationBuilder.RenameColumn()。还有RenameIndex()RenameTable() 和存储过程“sp_rename”(在 SQL Server 中)用于重命名外键。例如:

    migrationBuilder.Sql($"EXEC sp_rename 'dbo.{oldName}', '{newName}'");
    

    使用 SQL Server Management Studio 中的数据库脚本工具(rt-click on DB | Tasks | Generate Scripts...)生成架构脚本,有和没有 EF 迁移自定义,可以比较。然后你就会知道 EF 命名被保留了。

    编辑:添加了“EXEC ...”以支持生成独立的 T-SQL 脚本

    【讨论】:

      猜你喜欢
      • 2021-02-04
      • 1970-01-01
      • 2021-01-02
      • 2016-12-16
      • 2022-09-22
      • 1970-01-01
      • 1970-01-01
      • 2011-01-28
      • 2018-08-19
      相关资源
      最近更新 更多