Exercice - Configurer une migration
Dans cette leçon, vous allez créer des classes d’entité C# mappées à des tables dans une base de données SQLite locale. La fonctionnalité de migration EF Core produit des tables à partir de ces entités.
Les migrations sont un moyen de mettre à jour de façon incrémentielle le schéma de la base de données.
Obtenir les fichiers projet
Pour commencer, récupérez les fichiers projet. Pour obtenir les fichiers projet, plusieurs options s’offrent à vous :
- Utiliser GitHub Codespaces
- Cloner le dépôt GitHub
Si vous avez un runtime de conteneur compatible installé, vous pouvez également utiliser l’extension Dev Containers pour ouvrir le dépôt dans un conteneur avec les outils préinstallés.
Utiliser GitHub Codespaces
Un codespace est un IDE hébergé dans le cloud. Si vous utilisez GitHub Codespaces, accédez au dépôt dans votre navigateur. Sélectionnez Code, puis créez un codespace dans la branche main
.
Cloner le dépôt GitHub
Si vous n’utilisez pas GitHub Codespaces, vous pouvez cloner le dépôt GitHub du projet, puis ouvrir les fichiers en tant que dossier dans Visual Studio Code.
Ouvrez un terminal de commandes, puis clonez le projet à partir de GitHub en utilisant l’invite de commandes suivante :
git clone https://github.com/MicrosoftDocs/mslearn-persist-data-ef-core
Accédez au dossier mslearn-persist-data-ef-core, puis ouvrez le projet dans Visual Studio Code :
cd mslearn-persist-data-ef-core code .
Vérifier le code
Maintenant que vous disposez des fichiers projet à utiliser, voyons ce qui se trouve dans le projet et passons en revue le code.
- Le projet API web ASP.NET Core se trouve dans le répertoire ContosoPizza. Les chemins de fichiers auxquels nous faisons référence dans ce module sont relatifs au répertoire ContosoPizza.
- Services/PizzaService.cs est une classe de service qui définit les méthodes CRUD (création, lecture, mise à jour et suppression). Toutes les méthodes lèvent actuellement
System.NotImplementedException
. - Dans Program.cs,
PizzaService
est inscrit auprès du système d’injection de dépendances ASP.NET Core. - Controllers/PizzaController.cs est une valeur pour
ApiController
qui expose un point de terminaison pour les verbes HTTP POST, GET, PUT et DELETE. Ces verbes appellent les méthodes CRUD correspondantes surPizzaService
.PizzaService
est injecté dans le constructeurPizzaController
. - Le dossier Modèles contient les modèles que
PizzaService
etPizzaController
utilisent. - Les modèles d’entité, Pizza.cs, Topping.cs et Sauce.cs, ont les relations suivantes :
- Une pizza peut avoir une ou plusieurs garnitures.
- Une garniture peut être utilisée sur une ou plusieurs pizzas.
- Une pizza ne peut avoir qu’une seule sauce, mais une même sauce peut être utilisée sur plusieurs pizzas.
Générer l’application
Pour générer l’application dans Visual Studio Code :
Dans le volet Explorateur, cliquez avec le bouton droit sur le répertoire ContosoPizza et sélectionnez Ouvrir dans le terminal intégré.
Un volet de terminal délimité au répertoire ContosoPizza s’ouvre.
Générez l’application en utilisant la commande suivante :
dotnet build
Le code doit être généré sans avertissement ni erreur.
Ajouter des packages de NuGet et des outils de EF Core
Le moteur de base de données que vous utilisez dans ce module est SQLite. SQLite est un moteur de base de données léger basé sur des fichiers. C’est un bon choix pour le développement et les tests, et c’est aussi un bon choix pour les déploiements en production à petite échelle.
Notes
Comme indiqué précédemment, les fournisseurs de base de données dans EF Core sont enfichables. SQLite est un bon choix pour ce module, car il est léger et multiplateforme. Vous pouvez utiliser le même code pour travailler avec différents moteurs de base de données, tels que SQL Server et PostgreSQL. Vous pouvez même utiliser plusieurs moteurs de base de données dans la même application.
Avant de commencer, ajoutez les packages obligatoires :
Dans le volet du terminal, exécutez la commande suivante :
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
Cette commande ajoute le package NuGet qui contient le fournisseur de bases de données EF Core SQLite et toutes ses dépendances, y compris les services EF Core courants.
Ensuite, exécutez cette commande :
dotnet add package Microsoft.EntityFrameworkCore.Design
Cette commande ajoute les packages obligatoires pour les outils EF Core.
Pour terminer, exécutez cette commande :
dotnet tool install --global dotnet-ef
Cette commande installe
dotnet ef
, l’outil que vous utilisez pour créer des migrations et la génération automatique de modèles.Conseil
Si
dotnet ef
est déjà installé, vous pouvez le mettre à jour en exécutantdotnet tool update --global dotnet-ef
.
Échafauder des modèles et DbContext
Vous allez à présent ajouter et configurer une implémentation de DbContext
. DbContext
est une passerelle qui vous permet d’interagir avec la base de données.
Cliquez avec le bouton droit sur le répertoire ContosoPizza et ajoutez un nouveau dossier appelé Data.
Dans le dossier Data, créez un fichier nommé PizzaContext.cs. Ajoutez le code suivant au fichier vide :
using Microsoft.EntityFrameworkCore; using ContosoPizza.Models; namespace ContosoPizza.Data; public class PizzaContext : DbContext { public PizzaContext (DbContextOptions<PizzaContext> options) : base(options) { } public DbSet<Pizza> Pizzas => Set<Pizza>(); public DbSet<Topping> Toppings => Set<Topping>(); public DbSet<Sauce> Sauces => Set<Sauce>(); }
Dans le code précédent :
- Le constructeur accepte un paramètre de type
DbContextOptions<PizzaContext>
. Le constructeur permet au code externe de passer la configuration. Ainsi, leDbContext
peut être partagé entre le code de test et le code de production, et même utilisé avec différents fournisseurs. - Les propriétés
DbSet<T>
correspondent aux tables à créer dans la base de données. - Les noms des tables correspondront aux noms des propriétés
DbSet<T>
dans la classePizzaContext
. Vous pouvez remplacer ce comportement si nécessaire. - Lorsqu’il est instancié,
PizzaContext
expose les propriétésPizzas
,Toppings
etSauces
. Les modifications que vous apportez aux collections que ces propriétés exposent sont propagées à la base de données.
- Le constructeur accepte un paramètre de type
Dans Program.cs, remplacez
// Add the PizzaContext
par le code suivant :builder.Services.AddSqlite<PizzaContext>("Data Source=ContosoPizza.db");
Le code précédent :
- Inscrit
PizzaContext
auprès du système d’injection de dépendances ASP.NET Core. - Spécifie qui
PizzaContext
utilise le fournisseur de base de données SQLite. - Définit une chaîne de connexion SQLite qui pointe vers un fichier local, ContosoPizza.db.
Remarque
SQLite utilise des fichiers de base de données locaux. Il est donc acceptable de coder en dur la chaîne de connexion. Pour les bases de données réseau telles que PostgreSQL et SQL Server, vous devez toujours stocker vos chaînes de connexion de manière sécurisée. Pour le développement local, utilisez le Gestionnaire de secrets. Pour les déploiements de production, envisagez d’utiliser un service comme Azure Key Vault.
- Inscrit
Également dans Program.cs, remplacez
// Additional using declarations
par le code suivant.using ContosoPizza.Data;
Ce code résout les dépendances de l’étape précédente.
Enregistrez toutes vos modifications. GitHub Codespaces enregistre automatiquement vos modifications.
Générez l’application dans le terminal en exécutant
dotnet build
. La génération doit normalement réussir sans avertissement ni erreur.
Créer et exécuter un projet de migration
Ensuite, créez une migration que vous pouvez utiliser pour créer votre base de données initiale.
Dans le terminal étendu au dossier de projet ContosoPizza, exécutez la commande suivante pour générer une migration et créer les tables de base de données :
dotnet ef migrations add InitialCreate --context PizzaContext
Dans la commande précédente :
- La migration est nommée : InitialCreate.
- L’option
--context
spécifie le nom de la classe dans le projet ContosoPizza, qui dérive deDbContext
.
Un nouveau répertoire Migrations apparaît à la racine du projet ContosoPizza. Le répertoire contient un fichier <timestamp>_InitialCreate.cs qui décrit les modifications de la base de données à traduire en script de modification du langage de définition de données (DDL).
Exécutez la commande suivante pour appliquer la migration InitialCreate :
dotnet ef database update --context PizzaContext
Cette commande applique la migration. Comme ContosoPizza.db n’existe pas, cette commande crée la migration dans le répertoire du projet.
Conseil
Toutes les plateformes prennent en charge l’outil
dotnet ef
. Dans Visual Studio sur Windows, vous pouvez utiliser les applets de commande PowerShellAdd-Migration
etUpdate-Database
dans la fenêtre intégrée Console du gestionnaire de package.
Inspecter la base de données
EF Core a créé une base de données pour votre application. Examinons ensuite le contenu de la base de données à l’aide de l’extension SQLite.
Dans le volet Explorateur, cliquez avec le bouton droit sur le fichier ContosoPizza.db et sélectionnez Ouvrir la base de données.
Un dossier SQLite Explorer apparaît dans le volet Explorateur.
Sélectionnez le dossier SQLite Explorer pour développer le nœud et tous ses nœuds enfants. Cliquez avec le bouton droit sur ContosoPizza.db et sélectionnez Afficher la table « sqlite_master » pour afficher le schéma complet de la base de données et les contraintes créées par la migration.
- Des tables correspondant à chaque entité ont été créées.
- Les noms des tableaux ont été extraits des noms des propriétés
DbSet
dansPizzaContext
. - Les propriétés nommées
Id
ont été déduites pour l’auto-incrémentation des champs de clé primaire. - Les conventions de nommage des contraintes de clé primaire et de clé étrangère d’EF Core sont respectivement
PK_<primary key property>
etFK_<dependent entity>_<principal entity>_<foreign key property>
. Les espaces réservés<dependent entity>
et<principal entity>
correspondent aux noms des classes d’entité.
Notes
Comme ASP.NET Core MVC, EF Core utilise une approche de type « convention plutôt que configuration ». Les conventions EF Core raccourcissent le temps de développement en inférant l’intention du développeur. Par exemple, EF Core infère une propriété nommée
Id
ou<entity name>Id
comme étant la clé primaire de la table générée. Si vous choisissez de ne pas adopter la convention d’affectation de noms, vous devez annoter la propriété avec l’attribut[Key]
ou la configurer en tant que clé dans la méthodeOnModelCreating
deDbContext
.
Modifier le modèle et mettre à jour le schéma de la base de données
Votre responsable chez Contoso Pizza vous communique de nouvelles exigences qui vous obligent à changer vos modèles d’entité. Dans les étapes suivantes, vous allez modifier les modèles en utilisant des attributs de mappage (parfois appelés « annotations de données »).
Dans Models\Pizza.cs, apportez les modifications suivantes :
- Ajoutez une directive
using
pourSystem.ComponentModel.DataAnnotations
. - Ajoutez un attribut
[Required]
avant la propriétéName
pour marquer la propriété comme requis. - Ajoutez un attribut
[MaxLength(100)]
avant la propriétéName
pour spécifier une longueur de chaîne maximale de 100.
Votre fichier Pizza.cs mis à jour doit ressembler au code suivant :
using System.ComponentModel.DataAnnotations; namespace ContosoPizza.Models; public class Pizza { public int Id { get; set; } [Required] [MaxLength(100)] public string? Name { get; set; } public Sauce? Sauce { get; set; } public ICollection<Topping>? Toppings { get; set; } }
- Ajoutez une directive
Dans Models\Sauce.cs, apportez les modifications suivantes :
- Ajoutez une directive
using
pourSystem.ComponentModel.DataAnnotations
. - Ajoutez un attribut
[Required]
avant la propriétéName
pour marquer la propriété comme requis. - Ajoutez un attribut
[MaxLength(100)]
avant la propriétéName
pour spécifier une longueur de chaîne maximale de 100. - Ajoutez une propriété
bool
nomméeIsVegan
.
Votre fichier Sauce.cs mis à jour doit ressembler au code suivant :
using System.ComponentModel.DataAnnotations; namespace ContosoPizza.Models; public class Sauce { public int Id { get; set; } [Required] [MaxLength(100)] public string? Name { get; set; } public bool IsVegan { get; set; } }
- Ajoutez une directive
Dans Models\Topping.cs, apportez les modifications suivantes :
Ajoutez des directives
using
pourSystem.ComponentModel.DataAnnotations
etSystem.Text.Json.Serialization
.Ajoutez un attribut
[Required]
avant la propriétéName
pour marquer la propriété comme requis.Ajoutez un attribut
[MaxLength(100)]
avant la propriétéName
pour spécifier une longueur de chaîne maximale de 100.Ajoutez une propriété
decimal
nomméeCalories
juste après la propriétéName
.Ajoutez une propriété
Pizzas
de typeICollection<Pizza>?
. Cette modification fait dePizza
-Topping
une relation plusieurs à plusieurs.Ajoutez un attribut
[JsonIgnore]
à la propriétéPizzas
.Important
Cet attribut empêche les entités
Topping
d’inclure la propriétéPizzas
lorsque le code de l’API web sérialise la réponse au format JSON. Sans ce changement, une collection sérialisée de garnitures inclut une collection de chaque pizza qui utilise la garniture. Chaque pizza de cette collection contient une collection de garnitures, chacun d’entre eux contenant une collection de pizzas. Ce type de boucle infinie est appelé référence circulaire et ne peut pas être sérialisé.
Votre fichier Topping.cs mis à jour doit ressembler au code suivant :
using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; namespace ContosoPizza.Models; public class Topping { public int Id { get; set; } [Required] [MaxLength(100)] public string? Name { get; set; } public decimal Calories { get; set; } [JsonIgnore] public ICollection<Pizza>? Pizzas { get; set; } }
Enregistrez toutes vos modifications et exécutez
dotnet build
.Exécutez la commande suivante pour générer une migration afin de créer les tables de base de données :
dotnet ef migrations add ModelRevisions --context PizzaContext
Cette commande crée une migration nommée : ModelRevisions.
Remarque
Vous verrez ce message : Une opération a été générée automatiquement, ce qui peut entraîner la perte de données. Passez en revue la migration pour déterminer la précision. Ce message s’est affiché car vous avez remplacé la relation un-à-plusieurs de
Pizza
àTopping
par une relation plusieurs-à-plusieurs, ce qui nécessite la suppression d’une colonne de clé étrangère existante. Étant donné que vous n’avez pas encore de données dans votre base de données, ce changement n’est pas problématique. Mais en règle générale, il est judicieux de vérifier la migration générée quand cet avertissement s’affiche pour vérifier qu’aucune donnée n’est supprimée ou tronquée par la migration.Exécutez la commande suivante pour appliquer la migration ModelRevisions :
dotnet ef database update --context PizzaContext
Dans la barre de titre du dossier SQLite Explorer, sélectionnez le bouton Actualiser les bases de données.
Dans le dossier SQLite Explorer, cliquez avec le bouton droit sur ContosoPizza.db. Sélectionnez Afficher la table « sqlite_master » pour afficher le schéma et les contraintes de la base de données complète.
Important
L’extension SQLite réutilise les onglets SQLite ouverts.
- Une table de jointure
PizzaTopping
a été créée pour représenter la relation plusieurs-à-plusieurs entre les pizzas et les garnitures. - De nouveaux champs ont été ajoutés à
Toppings
etSauces
.Calories
est défini en tant que colonnetext
, car SQLite n’a pas de typedecimal
correspondant.- De même,
IsVegan
est défini en tant que colonneinteger
. SQLite ne définit pas de typebool
. - Dans les deux cas, EF Core gère la traduction.
- La colonne
Name
de chaque table a été marquéenot null
, mais SQLite n’a pas de contrainteMaxLength
.
Conseil
Les fournisseurs de base de données EF Core mappent un schéma de modèle aux fonctionnalités d’une base de données spécifique. Bien que SQLite n’implémente pas de contrainte correspondante pour
MaxLength
, d’autres bases de données comme SQL Server et PostgreSQL le font.- Une table de jointure
Dans le dossier SQLite Explorer, cliquez avec le bouton droit sur la table
_EFMigrationsHistory
et sélectionnez Afficher la table. La table contient une liste de toutes les migrations appliquées à la base de données. Comme vous avez exécuté deux migrations, il existe deux entrées : une pour la migration InitialCreate et l’autre pour ModelRevisions.
Remarque
Dans cet exercice, des attributs de mappage (annotations de données) ont été utilisés pour mapper des modèles à la base de données. Au lieu de mapper des attributs, vous pouvez utiliser l’API Fluent ModelBuilder pour configurer des modèles. Les deux approches sont valides, mais certains développeurs ont une préférence pour une approche plutôt que l’autre.
Vous avez utilisé des migrations pour définir et mettre à jour un schéma de la base de données. Dans l’unité suivante, vous allez terminer les méthodes dans PizzaService
qui manipulent les données.