Gestion des migrations

À mesure que votre modèle change, les migrations sont ajoutées et supprimées dans le cadre du développement normal, et les fichiers de migration sont archivés dans le contrôle de code source de votre projet. Pour gérer les migrations, vous devez d’abord installer les outils en ligne de commande EF Core.

Conseil

Si DbContext se trouve dans un assembly différent du projet de démarrage, vous pouvez spécifier explicitement les projets cible et de démarrage dans les outils de la console du gestionnaire de package ou dans les outils CLI .NET Core.

Ajouter une migration

Une fois votre modèle modifié, vous pouvez ajouter une migration pour cette modification :

dotnet ef migrations add AddBlogCreatedTimestamp

Le nom de la migration peut être utilisé comme un message de validation dans un système de gestion de versions. Par exemple, vous pouvez choisir un nom tel que AddBlogCreatedTimestamp si la modification est une nouvelle propriété CreatedTimestamp sur votre entité Blog.

Trois fichiers sont ajoutés à votre projet sous le répertoire Migrations :

  • XXXXXXXXXXXXXX_AddCreatedTimestamp.cs : fichier principal des migrations. Contient les opérations nécessaires à l’application de la migration (dans Up) et à sa restauration (dans Down).
  • XXXXXXXXXXXXXX_AddCreatedTimestamp.Designer.cs : fichier de métadonnées des migrations. Contient des informations utilisées par EF.
  • MyContextModelSnapshot.cs : instantané de votre modèle actuel. Permet de déterminer ce qui a changé pendant l’ajout de la migration suivante.

L’horodatage dans le nom des fichiers permet de conserver ces derniers dans l’ordre chronologique et de voir ainsi la progression des modifications.

Espaces de noms

Vous êtes libre de déplacer les fichiers Migrations et de changer leur espace de noms manuellement. Les migrations sont créées en tant que sœurs de la dernière migration. Vous pouvez également spécifier le répertoire au moment de la génération comme suit :

dotnet ef migrations add InitialCreate --output-dir Your/Directory

Remarque

Vous pouvez également modifier l’espace de noms indépendamment du répertoire avec --namespace.

Personnaliser le code de migration

Bien qu’EF Core crée généralement des migrations précises, vous devez toujours passer en revue le code et vous assurer qu’il correspond à la modification souhaitée ; dans certains cas, il est même nécessaire de le faire.

Renommages de colonne

L’un des exemples notables où la personnalisation des migrations est requise consiste à renommer une propriété. Par exemple, si vous renommez une propriété Name en FullName, EF Core génère la migration suivante :

migrationBuilder.DropColumn(
    name: "Name",
    table: "Customers");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customers",
    nullable: true);

EF Core est généralement incapable de savoir quand l’intention consiste à supprimer une colonne et à en créer une (deux modifications distinctes) et quand une colonne doit être renommée. Si la migration ci-dessus est appliquée telle qu’elle est, tous vos noms de clients seront perdus. Pour renommer une colonne, remplacez la migration générée ci-dessus par les éléments suivants :

migrationBuilder.RenameColumn(
    name: "Name",
    table: "Customers",
    newName: "FullName");

Conseil

Le processus de structuration de migration vous avertit quand une opération peut entraîner une perte de données (par exemple la suppression d’une colonne). Si cet avertissement s’affiche, veillez particulièrement à examiner si le code de migration est exact.

Ajout de SQL brut

Bien que le renommage d’une colonne puisse être effectué via une API intégrée, dans de nombreux cas, ce n’est pas possible. Par exemple, nous souhaitons peut-être remplacer les propriétés existantes FirstName et LastName par une propriété FullName unique et nouvelle. La migration générée par EF Core sera la suivante :

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

Comme précédemment, cela entraînerait une perte de données indésirable. Pour transférer les données à partir des anciennes colonnes, nous réorganisons les migrations et introduisons une opération SQL brute comme suit :

migrationBuilder.AddColumn<string>(
    name: "FullName",
    table: "Customer",
    nullable: true);

migrationBuilder.Sql(
@"
    UPDATE Customer
    SET FullName = FirstName + ' ' + LastName;
");

migrationBuilder.DropColumn(
    name: "FirstName",
    table: "Customer");

migrationBuilder.DropColumn(
    name: "LastName",
    table: "Customer");

Modifications arbitraires via SQL brut

SQL brut peut également être utilisé pour gérer les objets de base de données dont EF Core n’est pas conscient. Pour ce faire, ajoutez une migration sans apporter de modification de modèle ; une migration vide est générée, que vous pouvez ensuite remplir avec les opérations SQL brutes.

Par exemple, la migration suivante crée une procédure stockée SQL Server :

migrationBuilder.Sql(
@"
    EXEC ('CREATE PROCEDURE getFullName
        @LastName nvarchar(50),
        @FirstName nvarchar(50)
    AS
        RETURN @LastName + @FirstName;')");

Conseil

EXEC est utilisée lorsqu’une instruction doit être la première ou une seule dans un lot SQL. Elle peut aussi être utilisée pour contourner les erreurs d’analyseur dans les scripts de migration idempotents qui peuvent se produire lorsque des colonnes référencées n’existent pas actuellement sur une table.

Cela peut être utilisé pour gérer n’importe quel aspect de votre base de données, y compris :

  • Procédures stockées
  • Recherche en texte intégral
  • Functions
  • Déclencheurs
  • Les vues

Dans la plupart des cas, EF Core encapsule automatiquement chaque migration dans sa propre transaction lors de l’application des migrations. Malheureusement, certaines opérations de migration ne peuvent pas être effectuées dans une transaction dans certaines bases de données ; dans ce cas, vous pouvez refuser la transaction en passant suppressTransaction: true à migrationBuilder.Sql.

Supprimer une migration

Parfois, vous ajoutez une migration et réalisez que vous devez apporter des modifications supplémentaires à votre modèle EF Core avant de l’appliquer. Pour supprimer la dernière migration, utilisez cette commande.

dotnet ef migrations remove

Après avoir supprimé la migration, vous pouvez apporter les modifications supplémentaires au modèle et la rajouter.

Avertissement

Évitez de supprimer les migrations qui ont déjà été appliquées aux bases de données de production. Si vous faites cela, vous ne pourrez pas rétablir ces migrations à partir des bases de données et pourrez interrompre les hypothèses effectuées par les migrations suivantes.

Liste des migrations

Vous pouvez répertorier toutes les migrations existantes comme suit :

dotnet ef migrations list

Vérifier si des modifications de modèle sont en attente

Remarque

Cette fonctionnalité a été ajoutée dans EF Core 8.0.

Parfois, vous pourrez vouloir vérifier si des modifications ont été apportées au modèle depuis la dernière migration. Cela peut vous aider à savoir quand vous ou un collègue avez oublié d’ajouter une migration. Une des manières de le faire est d’utiliser cette commande.

dotnet ef migrations has-pending-model-changes

Vous pouvez également effectuer cette vérification par programmation à l’aide de context.Database.HasPendingModelChanges(). Cela peut être utilisé pour écrire un test unitaire qui échoue lorsque vous oubliez d’ajouter une migration.

Réinitialisation de toutes les migrations

Dans certains cas extrêmes, il peut être nécessaire de supprimer toutes les migrations et de recommencer. Cette opération peut être facilement effectuée en supprimant votre dossier Migrations et en supprimant votre base de données ; à ce stade, vous pouvez créer une migration initiale qui contiendra l’intégralité de votre schéma actuel.

Il est également possible de réinitialiser toutes les migrations et d’en créer une seule sans perdre vos données. Ceci est parfois appelé une « action squash » et implique du travail manuel :

  1. Sauvegardez votre base de données, au cas où quelque chose se passe mal.
  2. Dans votre base de données, supprimez toutes les lignes de la table d’historique des migrations (p. ex. DELETE FROM [__EFMigrationsHistory] sur SQL Server).
  3. Supprimez votre dossier Migrations.
  4. Créez une nouvelle migration et générez un script SQL pour celle-ci (dotnet ef migrations script).
  5. Insérez une seule ligne dans l’historique des migrations pour enregistrer que la première migration a déjà été appliquée, car vos tables sont déjà là. L’insertion SQL est la dernière opération dans le script SQL généré ci-dessus et ressemble à ce qui suit (n’oubliez pas de mettre à jour les valeurs) :
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');

Avertissement

Tout code de migration personnalisé est perdu lorsque le dossier Migrations est supprimé. Toutes les personnalisations doivent être appliquées manuellement à la nouvelle migration initiale afin d’être conservées.

Ressources supplémentaires