如何在Entity Framework 5 Code First迁移中重命名数据库列而不丢失数据?

80

我成功地使用EF 5.0 Code First Migrations运行了默认的ASP.NET MVC 4模板。然而,当我更新一个模型属性名称时,对应的表列数据会被EF 5.0删除。

有没有一种自动化的方式可以重命名表列而不丢失数据?

8个回答

121

手动编辑迁移的UpDown方法,使用RenameColumn方法替换自动生成的AddColumnDropColumn


10
注意带有点号的表名。RenameColumn 生成一个 sp_rename 的 T-SQL 语句,它在内部使用了 parsename 函数,该函数有一些限制。因此,如果你的表名中带有点号,例如 "SubSystemA.Tablename",那么请使用:RenameColumn("dbo.[SubSystemA.Tablename]", "OldColumnName", "NewColumnName"); - Ilan
我认为这个答案假设您已经将 AutomaticMigration = true。然后,执行命令Add-Migration renameColumnXXX。之后检查生成的迁移文件并删除 DropColumnAddColumn - RasikaSam
1
对于 EF Core,您可以像这样使用: migrationBuilder.RenameColumn(name: "oldname",table: "tablename",newName: "newname",schema: "schema"); https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.migrations.migrationbuilder.renamecolumn?view=efcore-5.0 - Chamika Sandamal

47

正如已经提到的,请用RenameColumn替换自动生成的 AddColumnDropColumn

例如:

namespace MyProject.Model.Migrations
{
    using System;
    using System.Data.Entity.Migrations;

    public partial class RenameMyColumn : DbMigration
    {
        public override void Up()
        {
            // Remove the following auto-generated lines
            AddColumn("dbo.MyTable", "NewColumn", c => c.String(nullable: false, maxLength: 50));
            DropColumn("dbo.MyTable", "OldColumn");

            // Add this line
            RenameColumn("dbo.MyTable", "OldColumn", "NewColumn");
        }

        public override void Down()
        {
            // Remove the following auto-generated lines
            AddColumn("dbo.MyTable", "OldColumn", c => c.String(nullable: false, maxLength: 50));
            DropColumn("dbo.MyTable", "NewColumn");

            // Add this line
            RenameColumn("dbo.MyTable", "NewColumn", "OldColumn");
        }
    }
}

27

如果您这样做,您可以让迁移为您调用RenameColumn:

[Column("NewName")]
public string OldName { get; set; }

这是生成的迁移文件:

    public override void Up()
    {
        RenameColumn(table: "Schema.MyTable", name: "OldName", newName: "NewName");
    }

    public override void Down()
    {
        RenameColumn(table: "Schema.MyTable", name: "NewName", newName: "OldName");
    }
如果您想让属性和数据库列具有相同的名称,则可以稍后重命名属性并删除Column特性。

1
还有一个有用的提示,您也可以在程序包管理器控制台中运行此命令:Update-Database -Script。然后,您可以随时运行 SQL sp_rename 命令。 :D - Jess
1
由于模型的属性名称也被引用,因此首选方法是使用该方法。在可选的第二步重命名属性时,我验证了生成了一个空迁移。 - bvj

5

在Code First Migration中重命名列有两个步骤:

  1. 第一步,您需要在所更改的列上方添加ColumnAttribute,然后运行update-database命令。

[Column("Content")]
public string Description { set; get; }

  1. 第二步,

    • 运行add-migration yournamechange命令以创建一个DbMigration局部类。

    • 将RenameColumn("yourDatabase","name","newName")方法添加到up和down方法中。

RenameColumn("yourDatabase","name","newName");

public override void Up()
  {
        RenameColumn("dbo.your_database", "oldColumn",          
       "newColumn");
  }


public override void Down()
  {
        RenameColumn("dbo.your_database", "newColumn", 
        "oldColumn");
  }

当您连接时,您的数据库和模型类将通过数据库中的name_column和模型中属性方法中的name_type进行通信。


4
现在,这个回答是基于我对EF4.3的了解,所以我希望迁移在EF5中大致相同:) 创建迁移后,您应该能够在Up和Down方法中添加代码,在删除旧属性和创建新属性之间移动属性数据。使用SQL()方法解决了这个问题,您可以输入原始SQL来执行数据移动。
在迁移的Up方法中:
SQL("update [TheTable] set [NewColumn] = [OldColumn]");

在Down()方法中:

SQL("update [TheTable] set [OldColumn] = [NewColumn]");

这种方法的缺点是你可能会把代码和你正在使用的数据库耦合在一起(因为你正在编写原始的DB特定SQL)。还有其他可用于数据移动的方法。
更多信息请参见这里: MSDN

3

补充Josh Gallagher的回答:

在某些地方,sp_RENAME语法被描述为:

sp_RENAME 'TableName.[OldColumnName]' , '[NewColumnName]', 'COLUMN'

然而,这实际上会在新列名中包含括号。

DbMigration的RenameColumn()方法可能会做同样的事情,因此在指定新列名时要避免使用括号。

此外,在Up()和Down()中自动生成的命令包括DropPrimaryKey()和AddPrimaryKey(),如果被重命名的列是主键的一部分,则不需要进行这些操作。使用RenameColumn()时,底层的sp_RENAME会自动更新主键(如果需要的话)。


3
Entity Framework Core 3.1.1 中,如果你需要重命名一列 - 请按以下方式添加迁移:
migrationBuilder.RenameColumn(
                                name: "oldname",
                                table: "tablename",
                                newName: "newname",
                                schema: "schema");

0

就像Josh Gallagher所说的那样,您可以使用up()来执行以下操作:

public override void Up()
        {

            RenameColumn("dbo.atable","oldname","newname");
            AddColumn("dbo.anothertable", "columname", c => c.String(maxLength: 250));

        }

我发现this对于入门迁移非常有帮助;)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接