<style> .reveal { font-size: 27px; } mark { background-color: rgba(50, 168, 82, .5) !important; } </style> # I-CH 151 Intégrer des bases de données dans des applications Web 5&#46; ORM EF Core © Selmir Hajruli & EPSIC 2021 --- # Introduction ORM - Object–relational mapping ![](https://i.imgur.com/toA6HqC.png =700x) Note: Que signifie réellement ORM ? Jusqu'à présent, nous avons créé nos `Character` en tant que modèles - ou classes - dans notre code. Ces modèles sont constitués de plusieurs propriétés comme un Id, un Name, des HitPoints, etc. En gros, tout cela constitue l'objet. Les bases de données comme SQL Server, SQLite, MySql, MariaDB et bien d'autres sont des bases de données relationnelles et sont constituées de tables pour sauvegarder des données et ces tables peuvent avoir des relations entre elles. C'est exactement la même chose avec nos modèles. Jusqu'à présent, nous n'avons qu'un seul modèle. Mais dès que nous ajouterons des compétences, par exemple, nos `Character` pourraient avoir des "skills" comme lancer des boules de feu en tant que mage. On retrouvera également cette relation dans la base de données. Il y aura une table pour les personnages, une autre pour les compétences et une autre pour la relation entre les personnages et les compétences. Dans le passé, les développeurs devaient établir ces relations manuellement dans la base de données. Avec un ORM comme Entity Framework Core, c'est de l'histoire ancienne. EF Core connaît nos modèles et sait quelles tables doivent être créées. Si les modèles changent, Entity Framework modifie les tables et les relations dans la base de données. Vous construisez d'abord votre code - vos modèles - et ensuite Entity Framework crée la base de données correspondante. (Code first) Il est également possible de construire d'abord les tables de la base de données et de laisser Entity Framework construire les modèles. (Database first) --- # EF Core Entity Framework Core * Mis en avant par Microsoft, régulièrement mis à jour (actuellement : version 5) * Bien documenté, bonne communauté * Parfaitement intégré au reste du framework .NET (validation, exceptions, Linq…) * Complet tout en restant suffisamment simple d’utilisation * Alternatives : * NHibernate * Dapper * LLBLGen * XPO * etc --- # Code first vs Database first - ==Db First== - Comme son nom l’indique, cette méthode implique qu'on a déjà modélisé notre base de données en SQL puis qu'on va générer des classes pour travailler avec ces données. C’est le Modèle Logique de Données qui fera le lien entre la base de données et l’ORM. - ==Code first== - Ce qu’un développeur sait faire de mieux, c’est coder. - On créer nos classes selon le besoin de l'application et ensuite EF Core génère une base données correspondant à notre besoin. --- # Installer EF Core * Depuis la racine de notre repo `Epsic.Rpg` * Pour se placer dans le folder de notre projet `cd .\src\Epsic.Rpg\` * Pour installer le package nécessaire dans notre projet `dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 3.*` * Pour installer le package nécessaire pour la génération de notre base `dotnet add package Microsoft.EntityFrameworkCore.Design --version 3.*` * Pour installer le tooling EF Core sur notre machine `dotnet tool install --global dotnet-ef --version 3.*` :::success `dotnet ef` pour valider l'installation. ✔🚀 ::: --- # DataContext - Pour utiliser EF Core nous avons besoin d'un `DataContext`. `DataContext` est une classe C# qui va nous permettre de requêter la base de données en créant une connexion à la base et en faisant l'intérmédiaire entre notre programme et notre DB. - Dans notre projet Epsic.Rpg créer un dossier `Data` - Dans ce dossier `Data` créer une classe `EpsicRpgDataContext` qui hérite de `DbContext` - Dans la classe `EpsicRpgDataContext` créer un constrcuteur prennant en paramètre une instance du type `DbContextOptions<DataContext>` et le renvoyant au constructeur parent `: base(options)` - Pour finir, créer une propriété publique de type `DbSet<Character>` nommée `Characters` avec un `get` et `set` publics. --- # DataContext ```csharp public class EpsicRpgDataContext : DbContext { public DbSet<Character> Characters { get; set; } public EpsicRpgDataContext(DbContextOptions<EpsicRpgDataContext> options) : base(options) { } } ``` --- # Setup & Injection - Dans le fichier `Startup.cs` ajouter, dans la méthode `ConfigureServices` : ```csharp services.AddDbContext<EpsicRpgDataContext>(x => x.UseSqlite(@"Data Source=EpsicRpg.db;")); ``` ```csharp public void ConfigureServices(IServiceCollection services) { services.AddControllers().AddJsonOptions(jsonOptions => { jsonOptions.JsonSerializerOptions.PropertyNamingPolicy = null; }); services.AddDbContext<EpsicRpgDataContext>(x => x.UseSqlite(@"Data Source=CustomerDB.db;")); services.AddSwaggerGen(); services.AddSingleton<ICharacterService, CharacterService>(); } ``` Note: - `.AddDbContext<EpsicRpgDataContext>` enregistre notre DataContext pour l'injection de dépendances. - `x.UseSqlite(@"Data Source=EpsicRpg.db;")` indique que l'on souhaite utiliser une base SQLite nommée "EpsicRpg" à la racine de notre projet. --- # Migrations - Une "migration" EF Core est une action qui va migrer le schéma de notre base données d'une version à une autre. Par exemple l'ajout d'une nouvelle table se fera via une migration. - Deux méthodes crées : - `Up()` utilisée pour passer de la version X à la version X+1 - `Down()` utilisée si besoin de rollback un changement, passage de la version X à la version X-1 - Dans notre cas, nous n'avons pas encore de base données, donc la première migration va générer le code permettant de créer notre base. --- # Première migration - Toujours dans le projet `Epsic.Rpg` éxceuter la commande : - `dotnet ef migrations add InitialCreate` ![](https://i.imgur.com/Jt2GU8a.png) - Ces fichiers sont utilisés par Entity Framework afin qu'il sache ce qu'il doit faire de cette migration. Ils fournissent des informations sur vos tables et vos champs qu'EF Core utilise pour construire la base de données. --- # Première migration #### **`20201129201557_InitialCreate.cs`** ```csharp protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.CreateTable( name: "Characters", columns: table => new { Id = table.Column<int>(nullable: false).Annotation("Sqlite:Autoincrement", true), Name = table.Column<string>(nullable: true), HitPoints = table.Column<int>(nullable: false), Strength = table.Column<int>(nullable: false), Defense = table.Column<int>(nullable: false), Intelligence = table.Column<int>(nullable: false), Class = table.Column<int>(nullable: false) }, constraints: table => { table.PrimaryKey("PK_Characters", x => x.Id); }); } ``` ```csharp protected override void Down(MigrationBuilder migrationBuilder) { migrationBuilder.DropTable(name: "Characters"); } ``` --- # Première DB Maintenant que l'on a généré le code qui va pouvoir créer notre base de données, on va pouvoir procéder à la création de celle-ci, pour ce faire, il faut simplement éxécuter la commande suivante : `dotnet ef database update` ![](https://i.imgur.com/oFoOHyN.png =400x) *si tout s'est bien passé, voici notre base de données 🤞🚀* Note: Pour "voir" notre base données, nous pouvons utiliser une extension VS Code nommée "[SQLite](https://marketplace.visualstudio.com/items?itemName=alexcvzz.vscode-sqlite)". 1.Chercher SQLite dans l'onglet "Extensions" de VS Code ![](https://i.imgur.com/YjgyhA4.png) 2. Cliquer sur installer 3. Appuyer sur `FI` ou `CTRL+SHIFT+P` et taper "sqlite" dans la commande palette : ![](https://i.imgur.com/yJTfT33.png) 4. Sélectionner "Open database" 5. Puis sélectionner votre base de données ![](https://i.imgur.com/kQdT67L.png) 6. Vous avez miantenant un onglet "SQLITE EXPLORER" qui est apparu dans votre colonne de gauche, et si vous appyuez dessus normalement vous voyez ça : ![](https://i.imgur.com/TIw9Zsr.png) 7. Un clic droit sur "Characters" + click sur "Show table" affichera le contenu de la table dans une nouvelle fenêtre. (c'est vide c'est normal 👻) --- # Première requête - Dans votre classe `CharacterService` demander une instance de `EpsicRpgDataContext` en paramètre. ```csharp public CharacterService(EpsicRpgDataContext context) ``` - Créer une varaible d'instance de type `EpsicRpgDataContext` nommée `_context` ```csharp private readonly EpsicRpgDataContext _context; ``` - Puis, instancier cette variable `_context` avec le `context` injecté via le constructeur : ```csharp _context = context; ``` - Pour finir, remplacer le retour de `GetAll()` par ```csharp _context.Characters.ToList(); ``` --- # Première requête ```csharp private readonly EpsicRpgDataContext _context; public CharacterService(EpsicRpgDataContext context) { _context = context; } public IList<Character> GetAll() { return _context.Characters.ToList();; } ``` --- # Logging - EF Core peut logguer toutes les requêtes qu'il effectue en base de données dans la console. - Pour ce faire, il suffit d'ajouter dans le fichier `appsettings.json`, la ligne suivante dans l'objet `Logging->LogLevel` : ``` "Microsoft.EntityFrameworkCore.Database.Command": "Information" ``` ```json { "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information", "Microsoft.EntityFrameworkCore.Database.Command": "Information" } }, "AllowedHosts": "*" } ``` ![](https://i.imgur.com/grgnSAx.png) --- # Premier CRUD - `EpsicRpgDataContext` nous permet via les `DbSet` comme `DbSet<Character>` d'accéder à une table de notre DB. - Via cette propriété on peu effectuer toutes les opérations CRUD - Au slide précédent nous avons retourné toute la table, mais grâce à LINQ (vu dans un précédent cours) l'on peut filtrer, grouper, ordrer, etc le contenu de la table avant de la retourner. - Pour les autres opération ==CREATE==, ==UPDATE== et ==DELETE== c'est la même chose, on doit récupérer des éléments via le ==READ==, les modifier et appeler `_context.SaveChanges()` pour persister les modifications en base. - À vous de jouer... 🏆 --- # Exercice 7 : CRUD :::info - git commit -am "finished ex6" - git fetch - git checkout ex7 ::: - Supprimer la liste `_characters` de `CharacterService` - Remplacer toutes les opérations effectuées maintenant dans cette liste par des opéaration qui s'opéreront en base de données via notre `_context` EF Core. - Tous les test, que l'on a déjà, devraient passer à la fin de l'exercice et le comportement de l'application ne devrait pas être altéré. - [Intro Microsoft](https://docs.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-3.1) - [Learn Entity Framework Core](https://www.learnentityframeworkcore.com/dbcontext/modifying-data)
{"metaMigratedAt":"2023-06-15T16:23:07.395Z","metaMigratedFrom":"YAML","title":"I-CH 151 - 5. ORM EF Core","breaks":true,"slideOptions":"{\"theme\":\"moonl\",\"spotlight\":{\"enabled\":false}}","contributors":"[{\"id\":\"2ff8bf3a-d09c-4308-a7a7-64e5fb1c4783\",\"add\":13405,\"del\":2131}]"}
    204 views