Restauration d'Entity Framework et suppression des mauvaises migrations

174

J'utilise EF 6.0 pour mon projet en C # avec des migrations manuelles et des mises à jour. J'ai environ 5 migrations sur la base de données, mais j'ai réalisé que la dernière migration était mauvaise et je ne la veux pas. Je sais que je peux revenir à une migration précédente, mais lorsque j'ajoute une nouvelle migration (fixe) et que j'exécute Update-Database, même la mauvaise migration est appliquée.

J'essayais de revenir à la migration précédente et de supprimer le fichier avec une mauvaise migration. Mais ensuite, lorsque j'essaie d'ajouter une nouvelle migration, j'obtiens une erreur lors de la mise à jour de la base de données, car le fichier de migration est corrompu (plus précisément, la première ligne de code renomme la table A en B et les lignes suivantes, EF essaie de mettre à jour la table avec nom A - c'est peut-être un bug EF).

Y a-t-il une requête que je peux exécuter, qui dirait à EF quelque chose comme "Oubliez la dernière migration comme elle n'a jamais existé, c'était mauvais"? Quelque chose comme Remove-Migration.

Edit1 J'ai trouvé la solution qui me convenait. Changement du modèle en bon état et exécution Add-Migration TheBadMigration -Force. Cela rééchafaudera la dernière migration non appliquée.

Quoi qu'il en soit, cela ne répond toujours pas complètement à la question initiale. Si je mets à jour la base de données vers la mauvaise migration, je n'ai pas trouvé de bon moyen de revenir en arrière et de créer une nouvelle migration, à l'exclusion de la mauvaise.

Merci

Martin Brabec
la source
J'ai dû redémarrer Visual Studio, puis il a commencé à fonctionner correctement. Cela m'est déjà arrivé à plusieurs reprises, toujours après avoir joué avec des migrations sans réellement mettre à jour la base de données, il se passe donc quelque chose d'étrange avec les outils.
Andrei Dvoynos

Réponses:

167

Vous avez 2 options:

  • Vous pouvez supprimer le Down de la mauvaise migration et le mettre dans une nouvelle migration (vous devrez également apporter les modifications suivantes au modèle). C'est effectivement en train de passer à une meilleure version.

    J'utilise cette option sur des choses qui sont allées à plusieurs environnements.

  • L'autre option consiste à exécuter réellement Update-Database –TargetMigration: TheLastGoodMigrationsur votre base de données déployée, puis à supprimer la migration de votre solution. C'est un peu l'alternative Hulk Smash et nécessite que cela soit effectué sur toute base de données déployée avec la mauvaise version.

    Remarque: pour réorganiser la migration, vous pouvez utiliser Add-Migration [existingname] -Force. Cependant, cela écrasera votre migration existante, assurez-vous donc de ne le faire que si vous avez supprimé la migration existante de la base de données. Cela revient à supprimer le fichier de migration existant et à exécuteradd-migration

    J'utilise cette option lors du développement.

Pas aimé
la source
1
L'option Hulk Smash ne fonctionne pas. Je n'ai pas encore appliqué la mauvaise migration à la base de données. J'ai essayé, mais cela ne fonctionnait pas, car les noms de table que j'ai spécifiés dans la question d'origine. La première option ne me plaît pas beaucoup, car il semble que je devrais changer le code de la migration. Si je le fais mal, je peux tout casser.
Martin Brabec
8
Si vous n'avez pas encore appliqué la mauvaise migration, rien ne vous empêche de la supprimer et de la rescaffolding ou de corriger la migration interrompue.
Pas aimé
4
Le 'hulk smash' est la réponse, cela fonctionne pour moi lors du développement et je veux ajouter quelque chose à la migration que j'ai ratée. Je pense que les raisons pour lesquelles cela n'a pas fonctionné pour Martin ne sont pas liées (ou probablement liées à la modification manuelle du schéma de base de données)
rethenhouser2
1
@BenRethmeier en règle générale, j'utilise l'option hulk smash uniquement pendant le développement. En prod, je crée toujours une nouvelle migration pour corriger le problème. La raison en est que vous avez besoin d'une intervention manuelle si vous rétrogradez la base de données. Je n'aime rien qui nécessite une intervention manuelle en prod.
Pas aimé le
1
HULK SMASH !!!! --- J'ai essayé d'être gentil mais EF ne jouait pas - Je suis revenu au dernier connu - (Fichiers de migration sauvegardés) Supprimé, Migration ajoutée - Force - Renommé au précédent et copié le code. la deuxième migration de la même façon - pas d'erreur - retour à la normale
Traci
127

Comme la question l'indique, cela s'applique à une migration dans un environnement de type développement qui n'a pas encore été publié.

Ce problème peut être résolu en suivant ces étapes: restaurez votre base de données vers la dernière bonne migration, supprimez la mauvaise migration de votre projet Entity Framework, générez une nouvelle migration et appliquez-la à la base de données. Remarque: à en juger par les commentaires, ces commandes exactes peuvent ne plus être applicables si vous utilisez EF Core.

Étape 1: restaurer une migration précédente

Si vous n'avez pas encore appliqué votre migration, vous pouvez ignorer cette partie. Pour restaurer votre schéma de base de données à un point précédent, exécutez la commande Update-Database avec l'option -TargetMigration spécifiez la dernière bonne migration. Si le code de votre structure d'entité réside dans un projet différent de votre solution, vous devrez peut-être utiliser l'option «-Project» ou changer le projet par défaut dans la console du gestionnaire de packages.

Update-Database TargetMigration: <name of last good migration>

Pour obtenir le nom de la dernière bonne migration, utilisez la commande 'Get-Migrations' pour récupérer une liste des noms de migration qui ont été appliqués à votre base de données.

PM> Get-Migrations
Retrieving migrations that have been applied to the target database.
201508242303096_Bad_Migration
201508211842590_The_Migration_applied_before_it
201508211440252_And_another

Cette liste affiche d'abord les migrations appliquées les plus récentes. Choisissez la migration qui se produit dans la liste après celle vers laquelle vous souhaitez rétrograder, c'est-à-dire celle appliquée avant celle que vous souhaitez rétrograder. Maintenant, émettez une base de données de mise à jour.

Update-Database TargetMigration: "<the migration applied before it>"

Toutes les migrations appliquées après celle spécifiée seront déclassées dans l'ordre en commençant par la dernière migration appliquée en premier.

Étape 2: supprimez votre migration du projet

remove-migration name_of_bad_migration

Si la remove-migrationcommande n'est pas disponible dans votre version d'Entity Framework, supprimez manuellement les fichiers de la migration indésirable de votre dossier 'Migrations' de projet EF. À ce stade, vous êtes libre de créer une nouvelle migration et de l'appliquer à la base de données.

Étape 3: ajoutez votre nouvelle migration

add-migration my_new_migration

Étape 4: appliquez votre migration à la base de données

update-database
David Sopko
la source
6
Avec EF Core, il semble que Get-Migrations a été supprimé.
Kevin Burton
1
Étape 2 ! - Fonctionnalité très utile. Comme @KevinBurton l'a mentionné. Et puis add-migration "new migration",update-database
Alexander Frolov
2
Update-Database –migration: "<la migration appliquée avant elle>" @David Sopko
Fuat
Merci @AlexanderFrolov J'ai mis à jour la solution pour refléter vos commentaires.
David Sopko
1
nous devons utiliser remove-migration après l'étape 2
Rahul
55

Pour ceux qui utilisent EF Core avec ASP.NET Core v1.0.0, j'ai eu un problème similaire et j'ai utilisé les commandes suivantes pour le corriger (le post de @ DavidSopko m'a orienté dans la bonne direction, mais les détails sont légèrement différents pour EF Core) :

Update-Database <Name of last good migration>
Remove-Migration

Par exemple, dans mon développement actuel, la commande est devenue

PM> Update-Database CreateInitialDatabase
Done.
PM> Remove-Migration
Done.
PM> 

Le Remove-Migration supprimera la dernière migration que vous avez appliquée. Si vous avez un scénario plus complexe avec plusieurs migrations à supprimer (je n'en avais que 2, l'initiale et la mauvaise), je vous suggère de tester les étapes d'un projet factice.

Il ne semble pas y avoir actuellement de commande Get-Migrations dans EF Core (v1.0.0), vous devez donc rechercher dans votre dossier migrations et vous familiariser avec ce que vous avez fait. Cependant, il existe une belle commande d'aide:

PM> get-help entityframework

Rafraîchissement de la base de données dans l'explorateur d'objets SQL Server VS2015, toutes mes données ont été préservées et la migration que je souhaitais annuler a disparu :)

Au départ, j'ai essayé Remove-Migration par lui-même et j'ai trouvé la commande d'erreur déroutante:

System.InvalidOperationException: La migration '...' a déjà été appliquée à la base de données. Désappliquez-le et réessayez. Si la migration a été appliquée à d'autres bases de données, envisagez d'annuler ses modifications à l'aide d'une nouvelle migration.

Il y a déjà des suggestions pour améliorer ce libellé, mais j'aimerais que l'erreur dise quelque chose comme ceci:

Exécutez Update-Database (dernier bon nom de migration) pour rétablir le schéma de base de données dans cet état. Cette commande annulera toutes les migrations qui ont eu lieu après la migration spécifiée vers Update-Database. Vous pouvez ensuite exécuter Remove-Migration (nom de migration à supprimer)

Le résultat de la commande d'aide EF Core suit:

 PM> get-help entityframework
                     _/\__
               ---==/    \\
         ___  ___   |.    \|\
        | __|| __|  |  )   \\\
        | _| | _|   \_/ |  //|\\
        |___||_|       /   \\\/\\

TOPIC
    about_EntityFrameworkCore

SHORT DESCRIPTION
    Provides information about Entity Framework Core commands.

LONG DESCRIPTION
    This topic describes the Entity Framework Core commands. See https://docs.efproject.net for information on Entity Framework Core.

    The following Entity Framework cmdlets are included.

        Cmdlet                      Description
        --------------------------  ---------------------------------------------------
        Add-Migration               Adds a new migration.

        Remove-Migration            Removes the last migration.

        Scaffold-DbContext          Scaffolds a DbContext and entity type classes for a specified database.

        Script-Migration            Generates a SQL script from migrations.

        Update-Database             Updates the database to a specified migration.

        Use-DbContext               Sets the default DbContext to use.

SEE ALSO
    Add-Migration
    Remove-Migration
    Scaffold-DbContext
    Script-Migration
    Update-Database
    Use-DbContext
Richard Logwood
la source
6

Vous pouvez aussi utiliser

Remove-Migration -Force

Cela rétablira et supprimera la dernière migration appliquée

Daniël Tulp
la source
4

Tout d'abord, mettez à jour votre dernière migration parfaite via cette commande:

Update-Database TargetMigration

Exemple:

Update-Database -20180906131107_xxxx_xxxx

Ensuite, supprimez manuellement votre migration inutilisée.

Abdus Salam Azad
la source
2
il devrait être: Update-Database -TargetMigration 20180906131107_xxxx_xxxx
Elger Mensonides
Update-Database 20180906131107_xxxx_xxxx(pas de trait d'union) a fonctionné pour moi. Aucune version de en TargetMigrationtant que commutateur ne fonctionnait. Ces commandes semblent être une cible mouvante (c'est-à-dire les modifier dans chaque version)?
Sum None
3

Depuis .NET Core 2.2, TargetMigrationsemble avoir disparu:

get-help Update-Database

NAME
    Update-Database

SYNOPSIS
    Updates the database to a specified migration.


SYNTAX
    Update-Database [[-Migration] <String>] [-Context <String>] [-Project <String>] [-StartupProject <String>] [<CommonParameters>]


DESCRIPTION
    Updates the database to a specified migration.


RELATED LINKS
    Script-Migration
    about_EntityFrameworkCore 

REMARKS
    To see the examples, type: "get-help Update-Database -examples".
    For more information, type: "get-help Update-Database -detailed".
    For technical information, type: "get-help Update-Database -full".
    For online help, type: "get-help Update-Database -online"

Donc, cela fonctionne pour moi maintenant:

Update-Database -Migration 20180906131107_xxxx_xxxx

Ainsi que (non -Migration commutateur):

Update-Database 20180906131107_xxxx_xxxx

Sur une note supplémentaire, vous ne pouvez plus supprimer proprement les dossiers de migration sans mettre votre instantané de modèle hors de synchronisation. Donc, si vous apprenez cela à la dure et que vous vous retrouvez avec une migration vide où vous savez qu'il devrait y avoir des changements, vous pouvez exécuter (aucun commutateur nécessaire pour la dernière migration):

Remove-migration

Il nettoiera le désordre et vous remettra là où vous devez être, même si le dernier dossier de migration a été supprimé manuellement.

Somme Aucun
la source
0

Pour EF 6, voici un one-liner si vous rééchafaudez beaucoup en développement. Mettez simplement à jour les variables, puis continuez à utiliser la flèche vers le haut dans la console du gestionnaire de packages pour rincer et répéter.

$lastGoodTarget = "OldTargetName"; $newTarget = "NewTargetName"; Update-Database -TargetMigration "$lastGoodTarget" -Verbose; Add-Migration "$newTarget" -Verbose -Force

Pourquoi est-ce nécessaire, demandez-vous? Vous ne savez pas quelles versions d'EF6 cela s'applique, mais si votre nouvelle cible de migration a déjà été appliquée, l'utilisation de '-Force' pour rééchafauder dans Add-Migration ne rééchafaudera pas, mais créera plutôt un nouveau fichier (c'est un bon mais parce que vous ne voudriez pas perdre votre «Down»). L'extrait ci-dessus fait d'abord le 'Down' si nécessaire, puis -Force fonctionne correctement pour rééchafauder.

madame
la source