Application des migrations

Une fois vos migrations ajoutées, elles doivent être déployées et appliquées à vos bases de données. Il existe différentes stratégies pour ce faire, certains étant plus appropriés pour les environnements de production, et d’autres pour le cycle de vie du développement.

Remarque

Quelle que soit votre stratégie de déploiement, inspectez toujours les migrations générées et testez-les avant de les appliquer à une base de données de production. Une migration peut supprimer une colonne lorsque l’intention devait le renommer ou échouer pour diverses raisons lorsqu’elle est appliquée à une base de données.

Scripts SQL

La méthode recommandée pour déployer des migrations vers une base de données de production consiste à générer des scripts SQL. Les avantages de cette stratégie sont les suivants :

  • Les scripts SQL peuvent être vérifiés pour s’assurer de leur exactitude ; ce qui est important, car l’application de modifications de schéma aux bases de données de production est une opération potentiellement dangereuse qui peut impliquer une perte de données.
  • Dans certains cas, les scripts peuvent être ajustés pour répondre aux besoins spécifiques d’une base de données de production.
  • Les scripts SQL peuvent être utilisés conjointement avec une technologie de déploiement et peuvent même être générés dans le cadre de votre processus CI.
  • Les scripts SQL peuvent être fournis à un administrateur de base de données et peuvent être gérés et archivés séparément.

Utilisation de base

Les éléments suivants génèrent un script SQL à partir d’une base de données vide vers la dernière migration :

dotnet ef migrations script

Avec From (To implicite)

L’exemple suivant génère un script SQL à partir de la migration donnée vers la dernière migration.

dotnet ef migrations script AddNewTables

Avec From et To

L’exemple suivant génère un script SQL à partir de la migration spécifiée from vers la migration spécifiée to.

dotnet ef migrations script AddNewTables AddAuditTable

Vous pouvez utiliser un from plus récent que le to afin de générer un script de restauration.

Avertissement

Prenez note des scénarios de pertes de données potentielles.

La génération de script accepte les deux arguments suivants pour indiquer quelle plage de migrations doit être générée :

  • La migration from doit être la dernière migration appliquée à la base de données avant l’exécution du script. Si aucune migration n’a été appliquée, spécifiez 0 (il s’agit de la valeur par défaut).
  • La migration to est la dernière migration à appliquer à la base de données après l’exécution du script. Par défaut, il s’agit de la dernière migration dans votre projet.

Scripts SQL Idempotent

Les scripts SQL générés ci-dessus peuvent uniquement être appliqués pour modifier votre schéma d’une migration vers une autre ; il est de votre responsabilité d’appliquer le script de manière appropriée et uniquement aux bases de données dans l’état de migration correct. EF Core prend également en charge la génération de scripts idempotents , qui vérifient en interne quelles migrations ont déjà été appliquées (via la table de l’historique des migrations) et n’appliquent qu’un seul élément manquant. Cela est utile si vous ne connaissez pas exactement la dernière migration appliquée à la base de données, ou si vous effectuez un déploiement sur plusieurs bases de données susceptibles d’être à une autre migration.

Les opérations suivantes génèrent des migrations idempotentes :

dotnet ef migrations script --idempotent

Outils de ligne de commande

Les outils en ligne de commande EF peuvent être utilisés pour appliquer des migrations à une base de données. Bien que productive pour le développement local et le test des migrations, cette approche n’est pas idéale pour la gestion des bases de données de production :

  • Les commandes SQL sont appliquées directement par l’outil, sans donner au développeur la possibilité de les inspecter ou de les modifier. Cela peut être dangereux dans un environnement de production.
  • Le Kit de développement logiciel (SDK) .NET et l’outil EF doivent être installés sur des serveurs de production et nécessitent le code source du projet.

Remarque

Chaque migration est appliquée dans sa propre transaction. Consultez le problème GitHub #22616 pour une discussion sur les améliorations futures possibles dans ce domaine.

Les mises à jour suivantes de votre base de données vers la dernière migration :

dotnet ef database update

Les mises à jour suivantes de votre base de données vers une migration donnée :

dotnet ef database update AddNewTables

Notez que cela peut également être utilisé pour restaurer une migration antérieure.

Avertissement

Prenez note des scénarios de pertes de données potentielles.

Pour plus d’informations sur l’application des migrations via les outils en ligne de commande, consultez la référence des outils EF Core.

Offres groupées

Les bundles de migration sont des exécutables à fichier unique qui peuvent être utilisés pour appliquer des migrations à une base de données. Ils répondent à certaines des lacunes du script SQL et des outils en ligne de commande :

  • L’exécution de scripts SQL nécessite des outils supplémentaires.
  • La gestion des transactions et le comportement continue-on-error de ces outils sont incohérents et parfois inattendus. Cela peut laisser votre base de données dans un état non défini si un échec se produit lors de l’application des migrations.
  • Les offres groupées peuvent être générées dans le cadre de votre processus CI et facilement exécutées ultérieurement dans le cadre de votre processus de déploiement.
  • Les bundles peuvent être exécutés sans installer le Kit de développement logiciel (SDK) .NET ou l’outil EF (ou même le runtime .NET, lorsqu’ils sont autonomes) et ne nécessitent pas le code source du projet.

Les éléments suivants génèrent un bundle :

dotnet ef migrations bundle

Les éléments suivants génèrent un bundle autonome pour Linux :

dotnet ef migrations bundle --self-contained -r linux-x64

Pour plus d’informations sur la création d’offres groupées, consultez la référence des outils EF Core.

efbundle

L’exécutable résultant est nommé efbundle par défaut. Il peut être utilisé pour mettre à jour la base de données vers la dernière migration. Il équivaut à exécuter dotnet ef database update ou Update-Database.

Arguments :

Argument Description
<MIGRATION> Migration cible. Si « 0 », toutes les migrations seront rétablies. Valeur par défaut de la dernière migration.

Options :

Option Court Description
--connection <CONNECTION> Chaîne de connexion à la base de données. La valeur par défaut est celle spécifiée dans AddDbContext ou OnConfiguring.
--verbose -v Afficher la sortie détaillée.
--no-color Ne colorisez pas la sortie.
--prefix-output Sortie de préfixe avec niveau.

L’exemple suivant applique les migrations vers une instance SQL Server locale à l’aide du nom d’utilisateur et du mot de passe spécifiés.

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password=myPassword'

Avertissement

N’oubliez pas de copier appsettings.json en même temps que votre bundle. Le bundle s’appuie sur la présence d’appsettings.json dans le répertoire d’exécution.

Exemple de bundle de migration

Un bundle a besoin de migrations à inclure. Celles-ci sont créées à l’aide dotnet ef migrations add de la procédure décrite dans Créer votre première migration. Une fois que vous avez des migrations prêtes à être déployées, créez un bundle à l’aide de dotnet ef migrations bundle. Par exemple :

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

La sortie est un exécutable adapté à votre système d’exploitation cible. Dans mon cas, il s’agit de Windows x64, donc j’obtiens un fichier efbundle.exe dans mon dossier local. L’exécution de cet exécutable applique les migrations contenues dans celui-ci :

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Comme avec dotnet ef database update ou Update-Database, les migrations sont appliquées à la base de données uniquement si elles n’ont pas déjà été appliquées. Par exemple, l’exécution du même bundle ne fait rien, car il n’existe aucune nouvelle migration à appliquer :

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.
PS C:\local\AllTogetherNow\SixOh>

Toutefois, si des modifications sont apportées au modèle et que d’autres migrations sont générées avec dotnet ef migrations add, elles peuvent être regroupées dans un nouvel exécutable prêt à appliquer. Par exemple :

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add SecondMigration
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add Number3
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle --force
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Conseil

L’option --force peut être utilisée pour remplacer l’offre groupée existante avec une nouvelle option.

L’exécution de ce nouveau bundle applique ces deux nouvelles migrations à la base de données :

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Par défaut, le pack utilise la chaîne de connexion de base de données à partir de la configuration de votre application. Toutefois, une autre base de données peut être migrée en transmettant la chaîne de connexion sur la ligne de commande. Par exemple :

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe --connection "Data Source=(LocalDb)\MSSQLLocalDB;Database=SixOhProduction"
Applying migration '20210903083845_MyMigration'.
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Remarque

Cette fois, les trois migrations ont été appliquées, car aucune d’entre elles n’avait encore été appliquée à la base de données de production.


Appliquer des migrations au moment de l’exécution

Il est possible pour l’application elle-même d’appliquer des migrations par programme, généralement au démarrage. Bien que productive pour le développement local et le test des migrations, cette approche n’est pas adaptée à la gestion des bases de données de production, pour les raisons suivantes :

  • Si plusieurs instances de votre application s’exécutent, les deux applications peuvent tenter d’appliquer la migration simultanément et échouer (ou pire, provoquer une altération des données).
  • De même, si une application accède à la base de données alors qu’une autre application la migre, cela peut entraîner des problèmes graves.
  • L’application doit avoir un accès élevé pour modifier le schéma de base de données. Il est généralement recommandé de limiter les autorisations de base de données de l’application en production.
  • Il est important de pouvoir restaurer une migration appliquée en cas de problème. Les autres stratégies fournissent cela facilement et hors de la boîte.
  • Les commandes SQL sont appliquées directement par le programme, sans permettre au développeur d’inspecter ou de les modifier. Cela peut être dangereux dans un environnement de production.

Pour appliquer des migrations par programmation, appelez context.Database.Migrate(). Par exemple, une application ASP.NET classique peut effectuer les opérations suivantes :

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        db.Database.Migrate();
    }

    host.Run();
}

Notez que Migrate() s’appuie sur le service IMigrator , qui peut être utilisé pour des scénarios plus avancés. Utilisez myDbContext.GetInfrastructure().GetService<IMigrator>() pour y accéder.

Avertissement

  • Envisagez attentivement avant d’utiliser cette approche en production. L’expérience a montré que la simplicité de cette stratégie de déploiement est compensée par les problèmes qu’elle crée. Envisagez plutôt de générer des scripts SQL à partir de migrations.
  • N’appelez pas EnsureCreated() avant Migrate(). EnsureCreated() ignore Migrations pour créer le schéma, ce qui entraîne l’échec de Migrate().