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.

Note

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.

Choisir une stratégie de déploiement

Pour le déploiement automatisé, utilisez un bundle de migration. Un bundle est un artefact de déploiement qui peut être généré dans CI et exécuté ultérieurement sans le sdk .NET, les outils EF Core ou le code source de l'application. Utilisez plutôt un script SQL lorsque le sql doit être examiné, modifié, archivé ou remis à un DBA avant d’être appliqué.

Pour le développement local, dotnet ef database update ou Update-Database est généralement l’option la plus simple. Les projets Aspire doivent utiliser l’intégration des migrations Aspire EF Core pour coordonner l’exécution de la migration locale et publier des bundles ou des scripts.

Strategy Utilisation recommandée Passer en revue SQL avant l’exécution Nécessite le Kit de développement logiciel (SDK) et la source lors de l’exécution Utilise le verrouillage de migration EF Exécute des délégués d’amorçage EF
Script SQL Déploiement contrôlé ou contrôlé par l’administrateur de base de données Oui Non Non Non
Bundle de migration Déploiement automatisé Non Non Oui Oui
Outils en ligne de commande EF Développement et test locaux Non Oui Oui Oui
Migration du runtime Applications qui acceptent des compromis de migration de démarrage Non Non Oui Oui

EF Core 9 et versions ultérieures utilisent le verrouillage de migration. Opérations synchrones et appel UseSeedingd’outils ; opérations asynchrones appelées UseAsyncSeeding.

Utilisez une identité distincte pour le déploiement qui a l’autorisation de modifier le schéma. L’identité utilisée par l’application au moment de l’exécution doit normalement avoir uniquement les autorisations dont l’application a besoin pour lire et écrire des données.

Scripts SQL

Les scripts SQL sont recommandés lorsque le processus de déploiement nécessite que le sql généré soit inspecté ou modifié avant l’exécution. 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

Par défaut, la commande écrit le script dans la sortie standard. Utilisez --output (ou -o) pour créer un artefact de déploiement avec un nom prévisible :

dotnet ef migrations script --idempotent --output artifacts/migrations.sql

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.

Warning

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.

Les scripts de migration mettent à jour une base de données existante. Provisionnez la base de données elle-même via votre processus de déploiement d’infrastructure ou d’administration de base de données avant d’appliquer le script. La création de base de données nécessite généralement une connexion différente, des autorisations élevées et une configuration spécifique au fournisseur.

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 que celles qui manquent. 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.

La prise en charge du script Idempotent dépend du fournisseur de base de données. Par exemple, SQLite ne prend actuellement pas en charge la génération de scripts de migration idempotents.

Les éléments suivants 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 sdk .NET et l'outil EF doivent être installés sur des serveurs de production et nécessitent le code source du projet.

** Voici comment mettre à jour votre base de données vers la dernière migration :

dotnet ef database update

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

dotnet ef database update AddNewTables

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

Warning

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.

Environnement et configuration

Les outils exécutent du code d’application pour construire le DbContext. La sélection du fournisseur, les chaînes de connexion et la configuration du modèle peuvent donc dépendre de l’environnement d’application. Les outils ef Core au moment de la conception utilisent l’environnement Development lorsque ni DOTNET_ENVIRONMENT n’est ASPNETCORE_ENVIRONMENT défini.

Définissez explicitement l’environnement lors de la génération d’un artefact de déploiement et lors de l’exécution d’un bundle. Par exemple, dans PowerShell :

$env:ASPNETCORE_ENVIRONMENT = 'Production'
dotnet ef migrations bundle --output artifacts\efbundle.exe
$env:ASPNETCORE_ENVIRONMENT = 'Production'
.\efbundle.exe --connection $env:DEPLOYMENT_CONNECTION_STRING

Ou dans un interpréteur de commandes compatible POSIX :

ASPNETCORE_ENVIRONMENT=Production \
    dotnet ef migrations bundle --output artifacts/efbundle

ASPNETCORE_ENVIRONMENT=Production \
    ./efbundle --connection "$DEPLOYMENT_CONNECTION_STRING"

Cela empêche également un bundle de charger des secrets utilisateur de développement de manière inattendue. Un environnement par défaut plus sûr pour les bundles est suivi par dotnet/efcore#36188. La sélection de l’environnement dans l’expérience de publication Visual Studio est suivie par dotnet/efcore#11950.

Ne stockez pas les chaînes de connexion de production dans le contrôle de code source ou ne les incorporez pas dans l’offre groupée. Fournissez la connexion de déploiement à partir du magasin de secrets du système de déploiement. L’identité de déploiement doit disposer d’autorisations de schéma ; l’identité normale de l’application ne doit généralement pas.

Bundles

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 de continuation en cas d'erreur 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 bundles utilisent le verrouillage de migration d’EF Core et exécutent la logique configurée UseSeeding .

Contrairement à un script SQL, un bundle ne fournit pas actuellement un moyen d’inspecter le sql qu’il exécutera ou répertoriera les migrations qu’il contient. Si votre déploiement nécessite une révision SQL, générez un script à la place. Les améliorations apportées à l’inspection des offres groupées sont suivies par dotnet/efcore#25872.

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

dotnet ef migrations bundle --output artifacts/efbundle

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

dotnet ef migrations bundle --self-contained --target-runtime linux-x64 --output artifacts/efbundle

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 Short 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 Préfixez la sortie avec le niveau.

L’exemple suivant applique les migrations vers une instance de SQL Server locale à l’aide du nom d’utilisateur et des informations d’identification spécifiés :

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}'

Pour restaurer la base de données, transmettez la migration qui doit rester appliquée. La transmission 0 rétablit toutes les migrations :

.\efbundle.exe PreviousMigration --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'
.\efbundle.exe 0 --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'

Warning

Une restauration exécute les Down opérations de chaque migration plus récente que la cible et peut entraîner une perte de données. Passez en revue et testez le comportement de restauration avant de l’utiliser sur les données de production.

Le code d’amorçage configuré s’exécute après une rétrogradation. Il doit tolérer le schéma de la migration cible, y compris un schéma d’application manquant lorsque la cible est 0.

Warning

Si la configuration du contexte lit appsettings.json, copiez les fichiers de paramètres requis en même temps que le bundle. Les fichiers de configuration sont résolus à partir du répertoire d’exécution du bundle. Ne placez pas de secrets de production dans ces fichiers ; fournissez-les via une source de configuration sécurisée ou l’option --connection .

Travaux de déploiement et de conteneurs

Générez l’offre groupée pendant la génération et exécutez-la en tant que travail de déploiement unique une fois la base de données saine. N’installez pas le Kit de développement logiciel (SDK) ou exécutez dotnet ef dans l’image de l’application et ne faites pas de migrations de réplica d’application à partir de son point d’entrée. Configurez la plateforme de déploiement pour ne pas redémarrer le conteneur de migration après sa sortie.

Pour les applications Aspire, AddEFMigrations vous pouvez coordonner les migrations pendant le développement local. Lors de la publication, PublishAsMigrationBundle peut émettre un bundle ou une image conteneur et PublishAsMigrationScript peut émettre un script SQL. Consultez Appliquer des migrations EF Core dans Aspire pour la configuration d’un travail one-shot pour Azure Container Apps, Docker Compose et Kubernetes.

L’exemple d’offre groupée de migration illustre deux migrations SQLite, l’amorçage idempotent, l’application de transfert et l’amorçage sécurisé par restauration.

Exemple de paquet 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, c’est Windows x64, donc je reçois un efbundle.exe déposé 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>

Tip

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 bundle utilise la chaîne de connexion de la base de données à partir de la configuration de votre application. Toutefois, une autre base de données peut être migrée en passant le 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>

Note

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. EF Core 9 et versions ultérieures protègent l’exécution de la migration avec un verrou à l’échelle de la base de données. Cela peut donc être acceptable pour les applications qui préfèrent un déploiement simple et peuvent tolérer le comportement de migration de démarrage. Une étape de déploiement de migration distincte est toujours recommandée lors de la révision, des informations d’identification à privilège minimum, du déploiement coordonné ou de la haute disponibilité.

Tenez compte des compromis suivants :

  • Pour les versions d’Entity Framework (EF) antérieures à la version 9, si plusieurs instances de votre application sont en cours d’exécution, les deux applications pourraient tenter d’appliquer la migration simultanément et échouer (ou pire, provoquer une corruption 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 annuler 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.MigrateAsync(). Par exemple, une application ASP.NET standard peut effectuer les opérations suivantes :

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

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

    host.Run();
}

Notez que MigrateAsync() 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.

Warning

  • Envisagez attentivement avant d’utiliser cette approche en production. Préférez un bundle de migration pour l’automatisation ou un script SQL lors de la révision et de l’approbation sont nécessaires.
  • N’appelez pas EnsureCreatedAsync() avant MigrateAsync(). EnsureCreatedAsync() ignore Migrations pour créer le schéma, ce qui entraîne l’échec de MigrateAsync().

Verrouillage de la migration

À partir d’EF Core 9, MigrateAsync et Migrate acquièrent automatiquement un verrou à l’échelle de la base de données avant d’appliquer des migrations. Cela protège contre l’altération de la base de données qui peut résulter de plusieurs instances d’application exécutant des migrations simultanément, ce qui est un scénario courant lors de l’application des migrations au moment de l’exécution. Le verrou est conservé pendant la durée de l’exécution de la migration, y compris tout code d’amorçage, et est automatiquement libéré une fois l’opération terminée.

Le verrouillage de la migration s’applique lorsque les migrations sont appliquées à l’aide de l’une des méthodes suivantes :

Les scripts SQL ne sont pas affectés par le verrouillage de la migration, car ils sont appliqués en dehors d’EF Core.

Note

À compter d’EF Core 9, l’appel Migrate() ou MigrateAsync() lève une exception lorsque le modèle a des modifications en attente par rapport à la dernière migration (ID RelationalEventId.PendingModelChangesWarningd’événement d’avertissement). Pour détecter cette condition avant le déploiement, utilisez la dotnet ef migrations has-pending-model-changes commande dans votre pipeline CI/CD. L’avertissement peut être supprimé via ConfigureWarnings (ignorant RelationalEventId.PendingModelChangesWarning) si nécessaire, mais cela n’est généralement pas recommandé dans les scénarios de production. Consultez la note relative à la rupture de compatibilité pour plus d’informations.

Warning

Le mécanisme de verrouillage varie considérablement entre les fournisseurs de base de données et peut impliquer des problèmes spécifiques au fournisseur. Par exemple, le fournisseur SQLite utilise une table de verrous qui peut devenir abandonnée si le processus se termine de façon inattendue. Consultez toujours la documentation de votre fournisseur pour plus d’informations.

Limites