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

Che*_*hev 101 c# sql-server entity-framework ef-migrations entity-framework-5

我重命名了几个实体及其导航属性,并在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");
    }
Run Code Online (Sandbox Code Playgroud)

所有我想要做的是重命名dbo.ReportSectionsdbo.ReportPages,然后dbo.ReportSectionGroupsdbo.ReportSections.然后,我需要外键列上的重命名dbo.ReportPages,从Group_IdSection_Id.

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

消息15248,级别11,状态1,过程sp_rename,行215参数@objname不明确或声明的@objtype(COLUMN)错误.消息4902,级别16,状态1,行10无法找到对象"dbo.ReportSections",因为它不存在或您没有权限.

我不是很容易弄清楚这里有什么问题.任何见解都会非常有帮助.

Che*_*hev 130

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

这就是我所需要的一切.重命名方法只是生成对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");
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意其中包含点的表名.`RenameColumn`生成一个`sp_rename` T-SQL语句,它在内部使用`parsename`,它有一些限制.因此,如果你有一个包含点的表名,例如"SubSystemA.Tablename",那么使用:`RenameColumn("dbo.[SubSystemA.Tablename]","OldColumnName","NewColumnName"); (25认同)
  • 这似乎更新了外键中引用的列,但它没有重命名FK本身.这是一种耻辱,但可能不是世界末日,除非你绝对需要稍后通过其名称来引用FK. (7认同)
  • @mikesigs你可以在迁移中使用`RenameIndex(..)`来重命名它 (7认同)

Hos*_*Rad 34

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

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

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Group_Id{get;set}
}
Run Code Online (Sandbox Code Playgroud)

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

public class ReportPages
{
    [Column("Section_Id")]                 //Section_Id
    public int Section_Id{get;set}
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为你只需要一次迁移,但仍然需要两步.1.添加属性并创建"重命名迁移"2.只需更改属性名称即可.而已.无论哪种方式,这只是为我节省了大量时间.谢谢! (5认同)
  • 还要注意这篇文章不是针对 EF 核心的 (4认同)
  • 如果您想对 EF Core 使用此方法,请务必执行两个单独迁移的两个步骤:ColumnChanged_A,然后 ColumnChanged_B。如果不这样做,您的 DBModelSnapshot 可能会引用旧的属性名称。(也许这总是会在以后的迁移中自行排序,但看起来仍然有点冒险) (2认同)

小智 13

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

这有几个好处:

  1. 这不仅会自动创建名称迁移,而且
  2. 它还可以美味地删除任何外键并根据新的表和列名称重新创建它们,为外键和constaints提供正确的名称.
  3. 所有这些都不会丢失任何表数据

例如,添加[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; }
}
Run Code Online (Sandbox Code Playgroud)

将生成迁移:

    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);
    }
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢,也只是想指出,在第一次迁移后,您通常会删除该属性并重命名表。**此时再运行一次迁移非常重要** - 您可以将其命名为“TempMigration”,然后删除实际的迁移,但重要的是上下文快照会使用新的类名进行更新。 (3认同)

mir*_*nd4 9

在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");
    }
Run Code Online (Sandbox Code Playgroud)

至于重命名列:

    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");
    }
Run Code Online (Sandbox Code Playgroud)