实体框架迁移重命名表和列

时间:2012-11-08 20:12:25

标签: c# sql-server entity-framework entity-framework-5 ef-migrations

我重命名了几个实体及其导航属性,并在EF 5中生成了一个新的迁移。通常在EF迁移中重命名,默认情况下它会删除对象并重新创建它们。这不是我想要的,所以我几乎不得不从头开始构建迁移文件。

    public override void Up()
    {
        DropForeignKey("dbo.ReportSectionGroups", "Report_Id", "dbo.Reports");
        DropForeignKey("dbo.ReportSections", "Group_Id", "dbo.ReportSectionGroups");
        DropForeignKey("dbo.Editables", "Section_Id", "dbo.ReportSections");
        DropIndex("dbo.ReportSectionGroups", new[] { "Report_Id" });
        DropIndex("dbo.ReportSections", new[] { "Group_Id" });
        DropIndex("dbo.Editables", new[] { "Section_Id" });

        RenameTable("dbo.ReportSections", "dbo.ReportPages");
        RenameTable("dbo.ReportSectionGroups", "dbo.ReportSections");
        RenameColumn("dbo.ReportPages", "Group_Id", "Section_Id");

        AddForeignKey("dbo.ReportSections", "Report_Id", "dbo.Reports", "Id");
        AddForeignKey("dbo.ReportPages", "Section_Id", "dbo.ReportSections", "Id");
        AddForeignKey("dbo.Editables", "Page_Id", "dbo.ReportPages", "Id");
        CreateIndex("dbo.ReportSections", "Report_Id");
        CreateIndex("dbo.ReportPages", "Section_Id");
        CreateIndex("dbo.Editables", "Page_Id");
    }

    public override void Down()
    {
        DropIndex("dbo.Editables", "Page_Id");
        DropIndex("dbo.ReportPages", "Section_Id");
        DropIndex("dbo.ReportSections", "Report_Id");
        DropForeignKey("dbo.Editables", "Page_Id", "dbo.ReportPages");
        DropForeignKey("dbo.ReportPages", "Section_Id", "dbo.ReportSections");
        DropForeignKey("dbo.ReportSections", "Report_Id", "dbo.Reports");

        RenameColumn("dbo.ReportPages", "Section_Id", "Group_Id");
        RenameTable("dbo.ReportSections", "dbo.ReportSectionGroups");
        RenameTable("dbo.ReportPages", "dbo.ReportSections");

        CreateIndex("dbo.Editables", "Section_Id");
        CreateIndex("dbo.ReportSections", "Group_Id");
        CreateIndex("dbo.ReportSectionGroups", "Report_Id");
        AddForeignKey("dbo.Editables", "Section_Id", "dbo.ReportSections", "Id");
        AddForeignKey("dbo.ReportSections", "Group_Id", "dbo.ReportSectionGroups", "Id");
        AddForeignKey("dbo.ReportSectionGroups", "Report_Id", "dbo.Reports", "Id");
    }

我要做的就是将dbo.ReportSections重命名为dbo.ReportPages,然后将dbo.ReportSectionGroups重命名为dbo.ReportSections。然后,我需要将dbo.ReportPages上的外键列从Group_Id重命名为Section_Id

我正在删除将表连接在一起的外键和索引,然后我重命名表和外键列,然后我再次添加索引和外键。我以为这会起作用,但我收到了SQL错误。

  

Msg 15248,Level 11,State 1,Procedure sp_rename,215行   参数@objname是不明确的,或者声明的@objtype(COLUMN)是错误的。   Msg 4902,Level 16,State 1,Line 10   无法找到对象“dbo.ReportSections”,因为它不存在或您没有权限。

我很难搞清楚这里有什么问题。任何见解都会非常有用。

8 个答案:

答案 0 :(得分:124)

没关系。我这样做比实际需要的更复杂。

这就是我所需要的一切。重命名方法只是生成对sp_rename系统存储过程的调用,我想这会处理所有事情,包括具有新列名的外键。

public override void Up()
{
    RenameTable("ReportSections", "ReportPages");
    RenameTable("ReportSectionGroups", "ReportSections");
    RenameColumn("ReportPages", "Group_Id", "Section_Id");
}

public override void Down()
{
    RenameColumn("ReportPages", "Section_Id", "Group_Id");
    RenameTable("ReportSections", "ReportSectionGroups");
    RenameTable("ReportPages", "ReportSections");
}

答案 1 :(得分:31)

如果您不喜欢手动编写/更改Migration类中所需的代码,可以按照两步方法自动生成所需的RenameColumn代码:

第一步使用ColumnAttribute引入新列名,然后添加迁移(例如Add-Migration ColumnChanged

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Group_Id{get;set}
}

第二步更改属性名称,并再次应用于程序包管理器控制台中的同一迁移(例如Add-Migration ColumnChanged -force

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Section_Id{get;set}
}

如果查看Migration类,您可以看到生成的自动代码为RenameColumn

答案 2 :(得分:10)

为了扩展Hossein Narimani Rad的答案,您可以分别使用System.ComponentModel.DataAnnotations.Schema.TableAttribute和System.ComponentModel.DataAnnotations.Schema.ColumnAttribute重命名表和列。

这有几个好处:

  1. 这不仅会自动创建名称迁移,而且还会
  2. 它还可以很好地删除任何外键并根据新的表名和列名重新创建它们,为外键和constaints提供正确的名称。
  3. 所有这些都不会丢失任何表格数据
  4. 例如,添加[Table("Staffs")]

    [Table("Staffs")]
    public class AccountUser
    {
        public long Id { get; set; }
    
        public long AccountId { get; set; }
    
        public string ApplicationUserId { get; set; }
    
        public virtual Account Account { get; set; }
    
        public virtual ApplicationUser User { get; set; }
    }
    

    将生成迁移:

        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropForeignKey(
                name: "FK_AccountUsers_Accounts_AccountId",
                table: "AccountUsers");
    
            migrationBuilder.DropForeignKey(
                name: "FK_AccountUsers_AspNetUsers_ApplicationUserId",
                table: "AccountUsers");
    
            migrationBuilder.DropPrimaryKey(
                name: "PK_AccountUsers",
                table: "AccountUsers");
    
            migrationBuilder.RenameTable(
                name: "AccountUsers",
                newName: "Staffs");
    
            migrationBuilder.RenameIndex(
                name: "IX_AccountUsers_ApplicationUserId",
                table: "Staffs",
                newName: "IX_Staffs_ApplicationUserId");
    
            migrationBuilder.RenameIndex(
                name: "IX_AccountUsers_AccountId",
                table: "Staffs",
                newName: "IX_Staffs_AccountId");
    
            migrationBuilder.AddPrimaryKey(
                name: "PK_Staffs",
                table: "Staffs",
                column: "Id");
    
            migrationBuilder.AddForeignKey(
                name: "FK_Staffs_Accounts_AccountId",
                table: "Staffs",
                column: "AccountId",
                principalTable: "Accounts",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
    
            migrationBuilder.AddForeignKey(
                name: "FK_Staffs_AspNetUsers_ApplicationUserId",
                table: "Staffs",
                column: "ApplicationUserId",
                principalTable: "AspNetUsers",
                principalColumn: "Id",
                onDelete: ReferentialAction.Restrict);
        }
    
        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropForeignKey(
                name: "FK_Staffs_Accounts_AccountId",
                table: "Staffs");
    
            migrationBuilder.DropForeignKey(
                name: "FK_Staffs_AspNetUsers_ApplicationUserId",
                table: "Staffs");
    
            migrationBuilder.DropPrimaryKey(
                name: "PK_Staffs",
                table: "Staffs");
    
            migrationBuilder.RenameTable(
                name: "Staffs",
                newName: "AccountUsers");
    
            migrationBuilder.RenameIndex(
                name: "IX_Staffs_ApplicationUserId",
                table: "AccountUsers",
                newName: "IX_AccountUsers_ApplicationUserId");
    
            migrationBuilder.RenameIndex(
                name: "IX_Staffs_AccountId",
                table: "AccountUsers",
                newName: "IX_AccountUsers_AccountId");
    
            migrationBuilder.AddPrimaryKey(
                name: "PK_AccountUsers",
                table: "AccountUsers",
                column: "Id");
    
            migrationBuilder.AddForeignKey(
                name: "FK_AccountUsers_Accounts_AccountId",
                table: "AccountUsers",
                column: "AccountId",
                principalTable: "Accounts",
                principalColumn: "Id",
                onDelete: ReferentialAction.Cascade);
    
            migrationBuilder.AddForeignKey(
                name: "FK_AccountUsers_AspNetUsers_ApplicationUserId",
                table: "AccountUsers",
                column: "ApplicationUserId",
                principalTable: "AspNetUsers",
                principalColumn: "Id",
                onDelete: ReferentialAction.Restrict);
        }
    

答案 3 :(得分:6)

在EF Core(2.0)中,我使用以下语句重命名表和列:

至于重命名表:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameTable(name: "OldTableName", schema: "dbo", newName: "NewTableName", newSchema: "dbo");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameTable(name: "NewTableName", schema: "dbo", newName: "OldTableName", newSchema: "dbo");
    }

至于重命名列:

    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(name: "OldColumnName", table: "TableName", newName: "NewColumnName", schema: "dbo");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.RenameColumn(name: "NewColumnName", table: "TableName", newName: "OldColumnName", schema: "dbo");
    }

答案 4 :(得分:2)

我在EF6(代码第一个实体重命名)中尝试了相同的操作。我只是重命名了类并使用包管理器控制台添加了迁移,并且自动为我生成了使用RenameTable(...)的迁移。我必须承认,我确保对实体的唯一更改是重命名它所以没有新列或重命名列,所以我不能确定这是EF6的东西还是只是EF(总是)能够检测到这种简单的迁移。

答案 5 :(得分:2)

在ef core中,您可以更改添加迁移后创建的迁移。然后做更新数据库。示例如下:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.RenameColumn(name: "Type", table: "Users", newName: "Discriminator", schema: "dbo");
}

protected override void Down(MigrationBuilder migrationBuilder)
{            
    migrationBuilder.RenameColumn(name: "Discriminator", table: "Users", newName: "Type", schema: "dbo");
}

答案 6 :(得分:1)

对于EF Core migrationBuilder.RenameColumn,通常效果很好,但有时您也必须处理索引。

migrationBuilder.RenameColumn(name: "Identifier", table: "Questions", newName: "ChangedIdentifier", schema: "dbo");

更新数据库时的错误消息示例:

Microsoft.Data.SqlClient.SqlException(0x80131904):索引 “ IX_Questions_Identifier”取决于列“ Identifier”。

索引“ IX_Questions_Identifier”取决于列“ Identifier”。

RENAME COLUMN标识符失败,因为一个或多个对象访问 此列。

在这种情况下,您必须像这样进行重命名:

migrationBuilder.DropIndex(
    name: "IX_Questions_Identifier",
    table: "Questions");

migrationBuilder.RenameColumn(name: "Identifier", table: "Questions", newName: "ChangedIdentifier", schema: "dbo");

migrationBuilder.CreateIndex(
    name: "IX_Questions_ChangedIdentifier",
    table: "Questions",
    column: "ChangedIdentifier",
    unique: true,
    filter: "[ChangedIdentifier] IS NOT NULL");

答案 7 :(得分:0)

可以将表名和列名指定为undefined映射的一部分。然后在迁移中没有必要这样做。

DbContext