Перейменування таблиць і стовпців міграцій Entity Framework


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.ReportSectionsв , dbo.ReportPagesа потім dbo.ReportSectionGroupsв dbo.ReportSections. Тоді мені потрібно перейменувати стовпець із зовнішнім ключем на dbo.ReportPagesвід Group_Idдо до Section_Id.

Я скидаю зовнішні ключі та індекси, що пов'язують таблиці разом, потім я перейменую таблиці та стовпець із зовнішнім ключем, потім знову додаю індекси та зовнішні ключі. Я припускав, що це буде працювати, але я отримую помилку SQL.

Msg 15248, рівень 11, стан 1, процедура sp_rename, рядок 215 Або параметр @objname неоднозначний, або заявлений @objtype (COLUMN) невірний. Msg 4902, рівень 16, стан 1, рядок 10 Неможливо знайти об’єкт "dbo.ReportSections", оскільки він не існує або у вас немає дозволів.

Мені непросто зрозуміти, що тут не так. Будь-яке розуміння було б надзвичайно корисним.


Який із наведених рядків не вдається? Чи можете ви простежити міграцію в Profiler SQL Server і перевірити відповідний SQL?
Альбін Суннанбо

Відповіді:


143

Не звертай уваги. Я робив цей шлях складнішим, ніж це було насправді.

Це все, що мені було потрібно. Методи перейменування просто генерують виклик до збереженої процедури 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_renameоператор T-SQL, який використовує parsenameвнутрішнє використання, яке має деякі обмеження. Тож якщо у вас є назва таблиці, у якій є крапки, наприклад "SubSystemA.Tablename", тоді використовуйте:RenameColumn("dbo.[SubSystemA.Tablename]", "OldColumnName", "NewColumnName");
Ilan

10
Це, здається, оновлює стовпці, на які посилається в Foreign Keys, але це не перейменовує сам FK. Це соромно, але, мабуть, не кінець світу, якщо вам абсолютно не потрібно посилатися на ФК пізніше за його назвою.
mikesigs

9
@mikesigs ви можете використовувати RenameIndex(..)для міграції, щоб перейменувати її
JoeBrockhaus

1
Я отримую виняток під час перейменування стовпця. ймовірно, тому, що таблиця перейменування досі не застосовується. Мені довелося розділити це на дві міграції
Джозе Мартінес

За допомогою EF6 використовуйте RenameTable(..)для перейменування ФК та ​​ПК. Це не правильно, але це те, що працювало для мене. Це метод, який створює правильний T-SQL ( execute sp_rename ...). Якщо ви зробите update-database -verbose, ви побачите це самі.
Джованні

44

Якщо вам не подобається писати / змінювати необхідний код у класі міграції вручну, ви можете дотримуватися двоетапного підходу, який автоматично зробить необхідний RenameColumnкод:

Перший крок Використовуйте, ColumnAttributeщоб ввести нове ім'я стовпця, а потім додати міграцію (наприклад Add-Migration ColumnChanged)

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

Крок другий змінить ім’я властивості та знову застосує до тієї ж міграції (наприклад Add-Migration ColumnChanged -force) у консолі диспетчера пакунків

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

Якщо ви подивитесь на клас міграції, ви побачите, що автоматично генерується код RenameColumn.


Як ви можете додати одну і ту ж міграцію двічі? Коли я спробую це, я отримую:The name 'Rename_SalesArea' is used by an existing migration.
Ендрю S,

подивіться на -forceпараметр під час використання додаткової міграції
Hossein Narimani Rad 13.03.18

2
також зверніть увагу, що ця публікація не є основою EF
Hossein Narimani Rad

6
Я думаю, вам потрібна лише одна міграція, але все-таки два кроки. 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
Здається, що за замовчуванням слід додати атрибут таблиці, робить речі набагато простішими.
патрік

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 ви можете змінити міграцію, створену після додавання міграції. А потім зробіть update-базу даних. Зразок наведено нижче:

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). Зміна первинного ключа викликає неполадки. Міграція спробує її видалити та створити нову. Тому вам потрібно відрегулювати це і зробити так, як відповідь Шева, перейменуйте стовпець.
CularBytes

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");
            });
     }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.