Entity Framework Migrationsがテーブルとカラムの名前を変更


118

いくつかのエンティティとそのナビゲーションプロパティの名前を変更し、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.ReportSectionsdbo.ReportPagesし、その後dbo.ReportSectionGroupsdbo.ReportSections。次に、外部キー列の名前をdbo.ReportPagesfrom Group_Idに変更する必要がありますSection_Id

テーブルをリンクしている外部キーとインデックスを削除してから、テーブルと外部キー列の名前を変更してから、インデックスと外部キーを再度追加しています。これはうまくいくと思っていましたが、SQLエラーが出ます。

メッセージ15248、レベル11、状態1、プロシージャsp_rename、行215パラメータ@objnameがあいまいであるか、要求された@objtype(COLUMN)が間違っています。メッセージ4902、レベル16、状態1、行10オブジェクト "dbo.ReportSections"が存在しないか、権限がないため、見つかりません。

ここで何が悪いのかを理解するのは簡単な時間ではありません。どんな洞察も途方もなく役立つでしょう。


上記の行のどれが失敗しますか?SQL Server Profilerで移行を追跡し、対応するSQLを確認できますか?
Albin Sunnanbo

回答:


143

気にしないで。私はこの方法を必要以上に複雑にしていました。

私が必要なのはこれだけでした。renameメソッドは、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");
}

29
ドットが含まれているテーブル名には注意してください。いくつかの制限がある内部使用を使用RenameColumnするsp_renameT-SQLステートメントを生成しますparsename。あなたはそれ例えば「SubSystemA.Tablename」でドットを持つテーブル名を持っている場合、次に使用:RenameColumn("dbo.[SubSystemA.Tablename]", "OldColumnName", "NewColumnName");
宜蘭

10
これは、外部キーで参照される列を更新するようですが、FK自体の名前は変更されません。これは残念ですが、後でFKを名前で絶対に参照する必要がない限り、おそらく世界の終わりではありません。
mikesigs 2014

9
RenameIndex(..)移行で使用して名前を変更できる@mikesigs
JoeBrockhaus

1
列の名前を変更すると例外が発生します。名前変更テーブルがまだ適用されていないためと考えられます。私はそれを2つのマイグレーションに分割しなければなりませんでした
Josue Martinez

EF6ではRenameTable(..)、FKとPKの名前を変更するために使用します。正しく聞こえませんが、私にとってはうまくいきました。これは、正しいT-SQL(execute sp_rename ...)を作成するメソッドです。update-database -verboseを実行すると、自分で確認できます。
ジョバンニ

44

Migrationクラスで必要なコードを手動で記述/変更したくない場合は、必要なコードを自動的に作成する2ステップのアプローチに従うことができますRenameColumn

ステップ1を使用しColumnAttributeて新しい列名を導入し、次に移行を追加します(例Add-Migration ColumnChanged

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

ステップ2でプロパティ名を変更Add-Migration ColumnChanged -forceし、パッケージマネージャーコンソールで同じ移行(例:)に再度適用します。

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

Migrationクラスを見ると、自動生成されたコードがであることがわかりますRenameColumn


同じ移行を2回追加するにはどうすればよいですか?私はこれをしようとすると、私が手に:The name 'Rename_SalesArea' is used by an existing migration.
アンドリュー・S

-forceadd-migrationを使用する際のパラメーターを確認してください
Hossein Narimani Rad

2
また、この投稿はEFコア向けではないことに注意してください
Hossein Narimani Rad

6
移行は1つで十分ですが、それでも2つのステップが必要です。1.属性を追加し、「移行の名前変更」を作成します。2.プロパティ名を変更するだけです。それでおしまい。いずれにせよ、これは私に多くの時間を節約してくれました。ありがとう!
クリスピー忍者

1
私はここに記載されている手順を実行し、それは成功しました。既存のデータは失われませんでした。データを失うことなく変更を加えることができます。ただし、安全のため、クラスのプロパティ名を変更した後で別の移行を実行します。
Manojb86

19

Hossein Narimani Radの答えを少し拡張するには、System.ComponentModel.DataAnnotations.Schema.TableAttributeおよびSystem.ComponentModel.DataAnnotations.Schema.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);
    }

1
table属性を追加するのがデフォルトであるようで、物事を非常に簡単にします。
パトリック

17

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

3

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

2

私はEF6(コードの最初のエンティティの名前変更)でも同じことを試しました。私は単にクラスの名前を変更し、パッケージマネージャーコンソールと出来上がりを使用して移行を追加しました。RenameTable(...)を使用した移行が自動的に生成されました。エンティティへの唯一の変更が名前の変更であることを確認したので、新しい列や列の名前は変更されなかったので、これがEF6の問題なのか、EFが(常に)このような単純な移行を検出できたのかはわかりません。


2
これは6.1.3で確認できます。テーブルの名前は正しく変更されます(の名前も変更することを忘れないDbSetでくださいDatabaseContext)。主キーを変更すると問題が発生します。移行はそれを削除して新しいものを作成しようとします。したがって、これを調整してChevの答えがそうであるように、列の名前を変更する必要があります。
CularBytes 2016年

1

テーブル名と列名は、のマッピングの一部として指定できます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");
            });
     }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.