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

我重命名了几个实体及其导航属性,并在 EF5中生成了一个新的迁移。与 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,第11层,状态1,过程 sp _ rename,第215行 要么参数@objecname 不明确,要么声明的@objectype (COLUMN)错误。 味精4902,16层,州1,10线 找不到对象“ dbo.ReportSections”,因为它不存在或者您没有权限。

我很难找出问题出在哪里,任何见解都会非常有帮助。

151055 次浏览

没关系,我把事情搞得太复杂了。

这就是我所需要的。重命名方法只生成对 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");
}

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

如果你不喜欢手工编写/修改需要的迁移类代码,你可以采用两步法自动生成所需的 RenameColumn代码:

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

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

步骤-第二步 更改属性名,并再次应用于 Package Manager Console 中的相同迁移(例如 Add-Migration ColumnChanged -force)

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

如果你看一下迁移类,你可以看到自动生成的代码是 RenameColumn

为了扩展 Hossein Narimani Rad 的答案,您可以使用 System 重命名表和列。组件模型。数据注释。图式。属性和系统。组件模型。数据注释。图式。分别为 ColumnAttribute。

这有几个好处:

  1. 这不仅会自动创建名称迁移,而且
  2. 它还将删除所有外键,并根据新的表和列名重新创建它们,从而为外键和包含赋予恰当的名称。
  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; }
}

将产生迁移:

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

表名和列名可以作为 DbContext映射的一部分指定。那么在迁移中就没有必要这样做了。

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

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

至于表的重命名:

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

在 efcore 中,您可以更改在添加迁移之后创建的迁移。然后更新数据库。以下是一个样本:

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

对于 EFCoremigrationBuilder.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 列标识符失败,因为一个或多个对象访问 本专栏。

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

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