web-dev-qa-db-fra.com

Entity Framework Migrations renommant des tables et des colonnes

J'ai renommé a quelques entités et leurs propriétés de navigation et généré une nouvelle migration dans EF 5. Comme d'habitude avec les renommements dans les migrations EF, par défaut, elle allait supprimer des objets et les recréer. Ce n’est pas ce que je voulais et j’ai donc dû créer le fichier de migration à partir de zéro.

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

Tout ce que j'essaie de faire, c'est de renommer dbo.ReportSections à dbo.ReportPages puis dbo.ReportSectionGroups à dbo.ReportSections. Ensuite, je dois renommer la colonne de clé étrangère sur dbo.ReportPages de Group_Id à Section_Id.

Je supprime les clés étrangères et les index liant les tables entre elles, puis je renomme les tables et la colonne de clé étrangère, puis j'ajoute à nouveau les index et les clés étrangères. J'ai supposé que cela allait marcher mais j'obtiens une erreur SQL.

Msg 15248, Niveau 11, État 1, Procédure sp_rename, ligne 215 Le paramètre @objname est ambigu ou le type prétendu (COLUMN) est incorrect. Msg 4902, niveau 16, état 1, ligne 10 Impossible de trouver l'objet "dbo.ReportSections" car il n'existe pas ou vous n'avez pas les autorisations.

Je ne peux pas facilement comprendre ce qui ne va pas ici. Toute idée serait extrêmement utile.

90
Chev

Ça ne fait rien. Je rendais ce chemin plus compliqué que nécessaire.

C'était tout ce dont j'avais besoin. Les méthodes de changement de nom génèrent simplement un appel à la procédure stockée système sp_rename et je suppose que cela s’occupe de tout, y compris des clés étrangères portant le nouveau nom de colonne.

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

Si vous n'aimez pas écrire/modifier manuellement le code requis dans la classe de migration, vous pouvez suivre une approche en deux étapes qui crée automatiquement le code RenameColumn requis:

Première étape Utilisez ColumnAttribute pour introduire le nouveau nom de colonne, puis ajoutez-migration (par exemple, Add-Migration ColumnChanged)

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

Deuxième étape changez le nom de la propriété et appliquez-le à la même migration (par exemple, Add-Migration ColumnChanged -force) dans la console du gestionnaire de packages

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

Si vous regardez la classe de migration, vous pouvez voir que le code généré automatiquement est RenameColumn.

32

Pour développer un peu la réponse de Hossein Narimani Rad, vous pouvez renommer une table et des colonnes en utilisant respectivement System.ComponentModel.DataAnnotations.Schema.TableAttribute et System.ComponentModel.DataAnnotations.Schema.ColumnAttribute.

Cela a quelques avantages:

  1. Non seulement cela créera automatiquement le nom des migrations, mais
  2. il supprimera également de manière délicieuse toutes les clés étrangères et les recréera contre les nouveaux noms de table et de colonne, en donnant les clés étrangères et les noms propres.
  3. Tout cela sans perdre les données de la table

Par exemple, en ajoutant [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; }
}

Générera la 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);
    }
12
Etienne Morin

Dans EF Core (2.0), j'utilise les instructions suivantes pour renommer les tables et les colonnes:

En ce qui concerne le changement de nom des 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");
    }

En ce qui concerne le changement de nom des colonnes:

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

Je viens d'essayer la même chose dans EF6 (code renommer une première entité). J'ai simplement renommé la classe et ajouté une migration à l'aide de la console du gestionnaire de paquets et le tour est joué, une migration à l'aide de RenameTable (...) a été générée automatiquement pour moi. Je dois admettre que je me suis assuré que la seule modification apportée à l'entité était de la renommer, donc pas de nouvelles colonnes ni de colonnes renommées. Je ne peux donc pas être sûr qu'il s'agisse d'un élément EF6 ou simplement que EF était (toujours) capable de détecter de telles migrations simples.

2
naskew

Les noms de table et de colonne peuvent être spécifiés dans le mappage de DbContext. Ensuite, il n'est pas nécessaire de le faire dans les 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");
            });
     }
}
0
Martin Staufcik