简体   繁体   English

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

[英]Entity Framework Migrations renaming tables and columns

I renamed aa couple entities and their navigation properties and generated a new Migration in EF 5. As is usual with renames in EF migrations, by default it was going to drop objects and recreate them.我重命名了一对实体及其导航属性,并在 EF 5 中生成了一个新的迁移。与 EF 迁移中的重命名一样,默认情况下它会删除对象并重新创建它们。 That isn't what I wanted so I pretty much had to build the migration file from scratch.这不是我想要的,所以我几乎不得不从头开始构建迁移文件。

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

All I'm trying to do is rename dbo.ReportSections to dbo.ReportPages and then dbo.ReportSectionGroups to dbo.ReportSections .我要做的就是将dbo.ReportSections重命名为dbo.ReportPages ,然后dbo.ReportSectionGroups重命名为dbo.ReportSections Then I need to rename the foreign key column on dbo.ReportPages from Group_Id to Section_Id .然后我需要将Group_Id dbo.ReportPages命名为Section_Id

I am dropping the foreign keys and indexes linking the tables together, then I am renaming the tables and the foreign key column, then I'm adding the indexes and foreign keys again.我删除将表链接在一起的外键和索引,然后重命名表和外键列,然后再次添加索引和外键。 I assumed this was going to work but I am getting a SQL error.我以为这会起作用,但我收到 SQL 错误。

Msg 15248, Level 11, State 1, Procedure sp_rename, Line 215 Either the parameter @objname is ambiguous or the claimed @objtype (COLUMN) is wrong.消息 15248,级别 11,State 1,过程 sp_rename,第 215 行参数 @objname 不明确或声明的 @objtype (COLUMN) 错误。 Msg 4902, Level 16, State 1, Line 10 Cannot find the object "dbo.ReportSections" because it does not exist or you do not have permissions.消息 4902,级别 16,State 1,第 10 行找不到 object “dbo.ReportSections”,因为它不存在或您没有权限。

I'm not having an easy time figuring out what is wrong here.我很难弄清楚这里出了什么问题。 Any insight would be tremendously helpful.任何见解都会非常有帮助。

Nevermind.没关系。 I was making this way more complicated than it really needed to be.我让这种方式变得比实际需要的更复杂。

This was all that I needed.这就是我所需要的。 The rename methods just generate a call to the sp_rename system stored procedure and I guess that took care of everything, including the foreign keys with the new column name.重命名方法只是生成对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");
}

If you don't like writing/changing the required code in the Migration class manually, you can follow a two-step approach which automatically make the RenameColumn code which is required:如果您不喜欢手动编写/更改 Migration 类中所需的代码,您可以按照两步方法自动RenameColumn所需的RenameColumn代码:

Step One Use the ColumnAttribute to introduce the new column name and then add-migration (eg Add-Migration ColumnChanged )第一步使用ColumnAttribute引入新的列名,然后添加迁移(例如Add-Migration ColumnChanged

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

Step-Two change the property name and again apply to same migration (eg Add-Migration ColumnChanged -force ) in the Package Manager Console第二步更改属性名称并再次应用于包管理器控制台中的相同迁移(例如Add-Migration ColumnChanged -force

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

If you look at the Migration class you can see the automatically code generated is RenameColumn .如果您查看 Migration 类,您可以看到自动生成的代码是RenameColumn

In EF Core, I use the following statements to rename tables and columns:在 EF Core 中,我使用以下语句重命名表和列:

As for renaming tables:至于重命名表:

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

As for renaming columns:至于重命名列:

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

To expand a bit on Hossein Narimani Rad's answer, you can rename both a table and columns using System.ComponentModel.DataAnnotations.Schema.TableAttribute and System.ComponentModel.DataAnnotations.Schema.ColumnAttribute respectively.要扩展 Hossein Narimani Rad 的回答,您可以分别使用 System.ComponentModel.DataAnnotations.Schema.TableAttribute 和 System.ComponentModel.DataAnnotations.Schema.ColumnAttribute 重命名表和列。

This has a couple benefits:这有几个好处:

  1. Not only will this create the the name migrations automatically, but这不仅会自动创建名称迁移,而且
  2. it will also deliciously delete any foreign keys and recreate them against the new table and column names, giving the foreign keys and constaints proper names.它还可以删除任何外键并根据新表和列名称重新创建它们,给出外键和常量名称。
  3. All this without losing any table data所有这一切都不会丢失任何表数据

For example, adding [Table("Staffs")] :例如,添加[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; }
}

Will generate the migration:将生成迁移:

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

I just tried the same in EF6 (code first entity rename).我刚刚在 EF6 中尝试了相同的方法(代码第一个实体重命名)。 I simply renamed the class and added a migration using the package manager console and voila, a migration using RenameTable(...) was automatically generated for me.我只是重命名了类并使用包管理器控制台添加了一个迁移,瞧,使用 RenameTable(...) 的迁移是自动为我生成的。 I have to admit that I made sure the only change to the entity was renaming it so no new columns or renamed columns so I cannot be certain if this is an EF6 thing or just that EF was (always) able to detect such simple migrations.我必须承认,我确保对实体的唯一更改是重命名它,因此没有新列或重命名列,因此我无法确定这是 EF6 的事情还是只是 EF(总是)能够检测到这种简单的迁移。

Table names and column names can be specified as part of the mapping of DbContext .表名和列名可以指定为DbContext映射的DbContext Then there is no need to do it in migrations.那么就没有必要在迁移中这样做了。

public class MyContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Restaurant>()
            .HasMany(p => p.Cuisines)
            .WithMany(r => r.Restaurants)
            .Map(mc =>
            {
                mc.MapLeftKey("RestaurantId");
                mc.MapRightKey("CuisineId");
                mc.ToTable("RestaurantCuisines");
            });
     }
}

In ef core, you can change the migration that was created after add migration.在 ef core 中,您可以更改添加迁移后创建的迁移。 And then do update-database.然后做更新数据库。 A sample has given below:下面给出了一个示例:

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

For EF Core migrationBuilder.RenameColumn usually works fine but sometimes you have to handle indexes as well.对于 EF Core migrationBuilder.RenameColumn通常工作正常,但有时您也必须处理索引。

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

Example error message when updating database:更新数据库时的示例错误消息:

Microsoft.Data.SqlClient.SqlException (0x80131904): The index 'IX_Questions_Identifier' is dependent on column 'Identifier'. Microsoft.Data.SqlClient.SqlException (0x80131904):索引“IX_Questions_Identifier”依赖于“Identifier”列。

The index 'IX_Questions_Identifier' is dependent on column 'Identifier'.索引 'IX_Questions_Identifier' 依赖于列 'Identifier'。

RENAME COLUMN Identifier failed because one or more objects access this column. RENAME COLUMN Identifier 失败,因为一个或多个对象访问此列。

In this case you have to do the rename like this:在这种情况下,您必须像这样重命名:

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");

Hossein Narimani Rad answer is really nice and straightforward. Hossein Narimani Rad的回答非常简单明了。 But it doesn't work for the EF core.但它不适用于 EF 核心。 because dotnet ef migration add doesn't have the --force option.因为dotnet ef migration add没有--force选项。

You have to do it this way.你必须这样做。

1- add [Column("NewColumnName")] 1-添加[Column("NewColumnName")]

2- create a migration dotnet ef migration add RenameSomeColumn 2-创建迁移dotnet ef migration add RenameSomeColumn

3- copy all the code in RenameSomeColumn.cs 3-复制RenameSomeColumn.cs中的所有代码

4- remove migration dotnet ef migrations remove 4-删除迁移dotnet ef migrations remove

5- remove [Column("NewColumnName")] and rename Property to NewColumnName 5-删除[Column("NewColumnName")]并将属性重命名为NewColumnName

6- again create migration dotnet ef migration add RenameSomeColumn 6- 再次创建迁移dotnet ef migration add RenameSomeColumn

7- past all the code copied from removed migration into new RenameSomeColumn.cs 7-过去的所有代码从删除迁移复制到新的RenameSomeColumn.cs

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM