Vous êtes sur la page 1sur 31

Support de cours

Architecture des SI I

Chapitre 3 : Entity Framework


Core
SOMMAIRE

Introduction 2

Qu’est-ce qu’un ORM? 2

Qu'est-ce que Entity Framework Core? 2

Historique 3

Architecture 4

Fonctionnalités 5

Approches 5

Entity Framework Core Code First 6


Création de la solution et installation de EF Core 7
Création du modèle de données dans le projet Domain 8
Implémentation du context dans le projet Data 9
Migrations 10
Conventions par défaut 16
Annotations 20
Types d’entité détenus 30
Stratégies d’héritage 30
Chargement des données associées 30

Références 31

1
Introduction
La première phase de développement d'une application est de déterminer la technologie à utiliser
pour l'implémentation (le langage de programmation) et la base de données à utiliser. La
question qui se pose dans ce cas est comment assurer le lien entre le langage de la base de
données qui est SQL et le langage de programmation que ce soit c#, vb...

Il existe bel et bien un moyen intermédiaire. Cet outil assure l’interaction entre les deux langages
de manière que la base de données puisse interpréter le code de développement et vis versa.

Qu’est-ce
ce qu’un ORM?
ORM (object-relational
relational mapping) est un outil qui sert à manipuler d'une manière automatisée les
données de l’objet vers la base de données relationnelle. L’ORM comprend trois parties
principales:

● Les objets de classe

● Les objets de la base de données relationnelle

● Les informations de Mappage pour les objets de la base de données relationnelles


(Tables, Vues et Procédures de stockage).

L’ORM est un outil qui génère des classes suite à l'interaction


l'interaction avec la base de données, comme

illustré ci-dessous:

Qu'est-ce
ce que Entity Framework Core?
Entity Framework Core (EFCore), comme tous les ORM(s), permet aux développeurs de
manipuler des données accessibles par des objets sans devoir se préoccuper de la base de
données et des tables.

EFCore prend en charge de nombreux fournisseurs de base de données: SQL Server, SQLite,
PostgreSQL, MySQL, Oracle DB ...

2
EFCore est destiné à être utilisé avec les applications .NET Core. Cependant, il peut également
être utilisé
tilisé avec les applications standard basées sur le framework .NET 4.5+.

La figure suivante illustre la place d'EFCore dans votre application:

Comme le montre la figure, EFCore fait partie de la couche Data. Il s'insère entre les classes de
domaine et la base
ase de données.

Historique
La première version de Entity Framework (EF v1) était incluse avec .NET Framework 3.5
Service Pack 1 et Visual Studio 2008 Service Pack 1, publiée le 11 août 2008.

Après plusieurs années et l'apparition de plusieurs versions de EF, Microsoft a décidé de rendre
.NET multiplateforme (fonctionne sous Windows, Linux et MacOS), ce qui signifie que la
prochaine version de EF serait une réécriture complète.

Le 27 juin 2016, la nouvelle version a été publiée sous le nom d'Entity Framework
Framewo Core 1.0,
avec .NET Core 1.0 et ASP.NET Core 1.0. Initialement, cette version s’appelait EF7, mais elle a
été renommée pour souligner qu'elle s'agissait d'une réécriture complète plutôt que d'une mise à
niveau incrémentielle et qu'elle ne remplace pas E
EF6.

Bien que Entity Framework Core 1.0 partage certaines similitudes conceptuelles avec les
versions précédentes de Entity Framework, il s'agit d'une toute nouvelle base de code conçue
pour être plus efficace, puissante, flexible, extensible, open source et multiplateforme et prend en
charge une nouvelle gamme de fournisseurs de base de données relationnelles et NOSQL.

La version la plus récente est Entity Framework Core 5.0.2 (EFCore 5), publiée le 12 janvier
2021.

3
EFCore 5 propose de nouvelles fonctionnalités qui ne sont pas implémentées dans EF6.
Cependant, toutes les fonctionnalités de EF6 ne sont pas actuellement iimplémentées dans
EFCore 5.

La tableau suivant illustre les dates de sortie des différentes versions de EFCore:

Version de EF Core Date de sortie

EF Core 1.0 Juin 2016

EF Core 1.1 Novembre 2016

EF Core 2.0 Août 2016

EF Core 3.0 Septembre 2019

EF Core 3.1 Décembre 2019

EF Core 5.0 Janvier 2021

EF Core 6.0 Novembre 2021 (date de sortie estimée)

Architecture

La figure suivante montre l'architecture globale de EF:

● EDM (Entity Data Model): est un ensemble de concepts qui décrivent la structure des
données, quelle que soit sa forme stockée. Il se compose de trois parties principales:
1. Modèle conceptuel: contient les entités et leurs relations.
2. Modèle de stockage: est le modèle de conception de base de données qui contient
des tables, vues, procédures stockées, ainsi que leurs relations et les clés.

4
3. Mapping: contient des informations sur la façon dont le modèle conceptuel est
mappé sur le modèle de stockage.
● LINQ to Entities: permet aux développeurs d'écrire des requêtes par rapport au modèle
conceptuel Entity Framework à l'aide du langage Visual Basic ou C#.
● EntitySQL: est un langage similaire à SQL qui vous permet d'interroger des entités dans
Entity Framework.
● Object Service: est un composant d'Entity Framework qui vous permet d’insérer, mettre
à jour et supprimer des données exprimées sous forme d'objets. Ce composant prend en
charge les requêtes LINQ (Language-Integrated Query) et les requêtes Entity SQL par
rapport aux types définis dans un modèle EDM (Modèle de données d'entité).
● Entity Client Data Provider: est un fournisseur de données utilisé par Entity
Framework. EntityClient utilise d’autres fournisseurs de données telles que le .NET
Framework pour accéder à la source de données. Par exemple, EntityClient utilise le
fournisseur de données .NET Framework pour SQL Server (SqlClient) pour accéder à la
base de données SQL Server.
● ADO.Net Data Provider: Cette couche communique avec la base de données en
utilisant ADO.Net standard.

Fonctionnalités
L'API EFCore inclut les fonctionnalités suivantes:

● Mapper les classes de domaine (entité) au schéma de la base de données.


● Traduire et exécuter des requêtes LINQ en SQL.
● Suivre les modifications survenues sur les entités au cours de leur durée de vie.
● Enregistrer les modifications dans la base de données.

Approches
Il existe deux approches de l’EFCore : Code First et Database First

● Approche Database First

5
Si vous avez déjà une base de données, EF permet de générer automatiquement un modèle dde
données (.edmx) qui contient des classes et des propriétés qui correspondent à des objets de la

base de données existantes telles que les tables et les colonnes.

● Approche Code First

Vous avez une base de données existante ou non, vous pouvez coder vos propres classes et
propriétés qui correspondent aux tables et colonnes et de les utiliser avec EF, sans fichier. Edmx.
EF peut également créer la base de données à partir des entités.

Entity Framework Core Code First


Avec l'approche Code First, on peut se concentrer sur la conception de la couche domaine et
commencer d' abord à créer des classes plutôt que de créer la base de données et ensuite créer les
classes qui correspondent à la conception de la base de données.

Le principe est de générer la base à partir d’un traitement de code. Pour se faire on à besoin
d’écrire les entités, de définir leurs propriétés de navigation, développer la classe context et
déclarer les entités qui vont être des tables en tant que DbSet. Le Mapping des classes dans la
base de données sera fait d’une manière implicite en utilisant les conventions par défaut de
EFCore CodeFirst. On peut également configurer les entités en utilisant Data Annotation ou
Fluent API afin de remplacer les conventions par défaut.

Nous allons détailler toutes les étapes à travers un exemple. Dans cet exemple nous allons suivre
l’architecture suivante:

6
● Création de la solution et installation de EF Core
La première étape à faire est la création de la solution qui contient les 3 couches ; deux projets de
type bibliothèque de classes (CodeFirst.Data et CodeFirst.Domain) et un projet de type
application console (CodeFirst.Console).

➢ Ajouter les références ent


entre les différents projets:
● Le projet Console se référencie aux projets Data et Domain.
● Le projet Data se référencie au projet Domain.

EFCore ne fait pas partie de .NET Core. Il est disponible sous forme de package NuGet.

➢ Installer Entity Framework Core dans la solution à travers le gestionnaire de package


NuGet.

7
● Création du modèle de données dans le projet Domain
La deuxième étape est la création des entités et leurs propriétés dans la couche Domain. Prenons
l’exemple suivant d’une application de gestio
gestion de compte bancaire.

➢ Ajouter les deux classes Agence et Compte dans le projet Domain.

namespace CodeFirst.Domain
{
public class Agence
{
public int AgenceId { get; set; }
public string Nom { get; set; }
public int NombreEmploye { get; set; }
public virtual ICollection<Compte> comptes { get; set; }
}

namespace CodeFirst.Domain
{
public class Compte
{
public int CompteId { get; set; }
public int RIB { get; set;; }
public virtual Agence Agence { get; set; }
}
}

8
● Implémentation du context dans le projet Data
Une fois les entités sont créées. L’approche Code First exige aussi la classe context dérivée de
DbContext. DbContext est une partie importante de l’EFCore. C’est la classe qui est responsable
de l'interaction avec la base de données.

La classe context contient les DbSet qui représentent les entités qui seront par la suite
transformées en tables. Elle redéfinit également les méthodes OnConfiguring et
OnModelCreating. On doit créer une instance de la classe context pour se connecter à la base de
données et enregistrer ou récupérer les données.

La méthode OnConfiguring permet de sélectionner et de configurer la source de données à l'aide


de DbContextOptionsBuilder. La méthode OnModelCreating permet de configurer le modèle à
l'aide de ModelBuilder Fluent API.

⮚ Créer une classe GestionCompteContext dans le projet Data

⮚ Ajouter l'héritage de DbContext

⮚ Créer le constructeur par défaut de la classe GestionCompteContext

Chaque DbContext instance doit être configurée pour utiliser un et un seul fournisseur de base de
données. (Les différentes instances d’un DbContext sous-type peuvent être utilisées avec
différents fournisseurs de bases de données, mais une seule instance ne doit en utiliser qu’une
seule.) Un fournisseur de base de données est configuré à l’aide d’un Use* appel spécifique.
Dans notre cas, on va utiliser le fournisseur de base de données SQL Server. Ces Use* méthodes
sont des méthodes d’extension implémentées par le fournisseur de base de données.

Afin que la méthode d’extension Use* puisse être utilisée, le package NuGet du fournisseur de
base de données (SQL Server) doit être installé.

La chaîne de connexion dans la méthode UseSqlServer fournit des informations sur la base de
données. DataSource spécifie le serveur de base de données à utiliser, InitialCatalog spécifie le
nom de la base de données à créer et IntegratedSecurity spécifie le mode d'authentification
Windows. EFCore utilisera cette chaîne de connexion lors de la génération de la base de
données.

⮚ Redéfinir la méthode OnConfiguring

⮚ Ajouter la chaîne de connexion

⮚ Installer EntityFrameworkCore.SqlServer dans le projet Data

⮚ Ajouter les DBSet des entités.

9
DbSet est une collection d’entités, donc généralement va prendre le nom de l’entité au pluriel.
Chaque DbSet représente une image d'une table, par exemple [DbSet<Compte> Comptes]
représente la table Comptes.

namespace CodeFirst.Data
{
public class GestionCompteContext : DbContext
{
public GestionCompteContext()
{

}
public DbSet<Agence> Agences { get; set; }
public DbSet<Compte> Comptes { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(@"Data Source=(localdb)\mssqllocaldb;Initial
Catalog=GestionCompteDB;Integrated Security=true");
base.OnConfiguring(optionsBuilder);
}
}
}

● Migrations
Après avoir créé les classes des entités et la classe context, il est temps d’utiliser les migrations
pour générer la base de données.

1. Installation des outils

Afin de pouvoir utiliser les migrations on doit installer les deux packages NuGet suivants:

⮚ Installer EntityFrameworkCore.Tools dans le projet Data

⮚ Installer EntityFrameworkCore.SqlServer.Design dans le projet Console

2. Génération de la base de données

EFCore CodeFirst dispose de deux commandes pour créer et appliquer une migration:

10
● Add-Migration:: pour enregistrer les modifications que vous avez apportées à vos
entités.
● Update-Database:: pour appliquer les modifications en attente à la base de données
basée sur la dernière version créée avec la commande Add-Migration
Migration.

Dans Visual Studio, ouvrez la console du gestionnaire de packages NuGet depuis Outils ->
Gestionnaire de packages NuGet -> Console du gestionnaire de packages.

⮚ Choisir le projet CodeFirst.Data de la liste déroulante de Projet par défaut.

⮚ Entrer la commande Add-Migration

⮚ Donner un nom à la migration (exemple: FirstMigration)

La première exécution de la commande Add-Migration va ajouter un dossier Migrations à notre


projet Data. Ce nouveau dossier contient deux fichiers :

● <contextclassname>ModelSnapshot.cs: Représente un instantané du modèle actuel.


Cette classe est utilisée pour déterminer ce qui a changé lors de la création d’une
nouvelle migration afin de pouvoir mettre la base de données à jour avec le modèle.
Cette classe est ajoutée au dossier Migrations lors de la création de la première
migration et mise à jour à chaque migration ultérieure.
● <timestamp>_<Migration Name>.cs:
Name> Le code dans cette migration représente les
objets qui sont créés dans la base de données. Cette classe contient une méthode Up()

11
qui contient des instructions pour la création et une autre méthode Down() pour la
suppression.

Après avoir créé une migration,


ation, on va générer la base de données à l'aide de la commande
Update-Database

⮚ Entrer la commande Update-Database dans la console du gestionnaire de packages.

EFCore CodeFirst a créé la base de données avec le nom et l'emplacement spécifiés dans la
chaînee de connexion dans la méthode UseSqlServer(). Il a créé une table pour chaque propriété
DbSet (Agences et Comptes) et chaque table contient des colonnes avec le type de donnée et la
longueur appropriée. Le nom des colonnes et le type des données correspondent
correspon aux propriétés
des classes d’entités. Comme le montre la figure suivante, les colonnes CompteId et AgenceId
sont des clés primaires et la colonne AgencesAgenceId est une clé étrangère.

Il s'agissait de la première migration pour créer une base de données. Désormais, chaque fois
qu'on ajoute ou on met à jour des classes ou des configurations de domaine, on doit synchroniser
la base de données avec le modèle à l'aide des commandes Add-Migration et Update-Database.

12
3. Evolution de modèle

EFCore utilise les migrations afin de pouvoir mettre à jour automatiquement le schéma de la
base de données lorsque le modèle change, sans perdre toutes les données existantes ou d’autres
objets de la base de données.

Après la création de la base de données, on a décidé d’ajouter une nouvelle classe d’entité.

13
⮚ Ajouter la classe Client dans le projet Domain.

namespace CodeFirst.Domain
{
public class Client
{
public int ClientId { get; set; }
public string Nom { get; set; }
public string Prenom { get; set; }
public virtual ICollection<Compte> Compte { get; set; }
}
}

⮚ Ajouter la propriété de navigation dans la classe Compte.

public virtual Client Client { get; set; }

Le modèle et la base de données de données ne sont plus synchronisés. Afin d’apporter les
modifications nécessaires à la base de données on doit créer une nouvelle migration.

Il est préférable de donner aux migrations un nom descriptif pour faciliter par la suite la
compréhension de l’historique du projet.

⮚ Exécuter la commande Add-Migration AddTableClient.

Comme il ne s’agit pas de la première migration du projet, EF Core compare maintenant le


modèle mis à jour à un instantané de l’ancien modèle avant ajout de la table, à savoir l’un des
fichiers générés par EF Core à l’ajout d’une migration. Sur la base de cette comparaison, EF
Core détecte qu’une table a été ajoutée et ajoute la migration correspondante.

⮚ Exécuter la commande Update-Database.

Cette fois, EF détecte que la base de données existe déjà. Par ailleurs, lors de l’application de la
première migration, elle a été enregistrée dans une table d’historique des migrations spéciale
dans la base de données. Ainsi, EF peut appliquer automatiquement la nouvelle migration
uniquement.

14
4. Suppression d’une migration

Parfois, on ajoute une migration et on réalise qu’on doit apporter des modifications
supplémentaires au modèle avant de l’appliquer. Pour supprimer la dernière migration, on utilise
la commande: Remove-Migration

5. Retour à un état précédent

Si on veut restaurer le schéma de la base de données à l'un des états précédents, on peut alors
utiliser la commande Update-DataBase avec le paramètre -Migration suivi du nom de la
migration.
Supposons qu’après l’application d’une première migration nommée MyFirstMigration, on a
modifié le modèle et on a créé une deuxième migration nommée MySecondMigration et on a
appliqué cette migration à la base de données à l'aide de la commande Update-Database. Mais,
pour une raison quelconque, on souhaite rétablir l'état précédent de la base de données. Dans ce
cas, on utilise la commande Update-Database -Migration MyFirstMigration pour rétablir la base
de données sur l'instantané de la première migration.

6. Les méthodes EnsureCreated et EnsureDeleted

Les méthodes EnsureCreated et EnsureDeleted fournissent une alternative légère aux migrations
pour la gestion du schéma de base de données. Ces méthodes sont utiles dans les scénarios où les
données sont temporaires et peuvent être supprimées lorsque le schéma est modifié. Par exemple
pendant le prototypage, les tests ou les caches locaux.

Certains fournisseurs (surtout non relationnels) ne prennent pas en charge les migrations. Pour
ces fournisseurs, EnsureCreated est souvent le moyen le plus simple d’initialiser le schéma de
base de données.

EnsureCreated et les migrations ne fonctionnent pas correctement ensemble. Si vous utilisez des
migrations, n’utilisez pas EnsureCreated pour initialiser le schéma.

La transition de EnsureCreated à des migrations n’est pas une expérience transparente. La façon
la plus simple de procéder consiste à supprimer la base de données et à la recréer à l’aide des
migrations. Si vous prévoyez d’utiliser des migrations à l’avenir, il est préférable de commencer
par les migrations au lieu d’utiliser EnsureCreated.

La méthode EnsureDeleted supprime la base de données, le cas échéant. Si vous ne disposez pas
des autorisations appropriées, une exception est levée.

15
● Conventions par défaut
Les conventions sont des règles par défaut à l'aide desquelles EFCore crée un schéma de base de
données basé sur les classes de domaine et de context sans aucune configuration supplémentaire.

7. Inclusion de types dans le modèle

Par Convention, les types d’entités qui sont exposés dans les propriétés DbSet de la classe
context sont inclus dans le modèle en tant qu’entités. Les types d’entités trouvés dans les
propriétés de navigation d’autres types d’entités sont également inclus ainsi que les types
d’entités qui sont spécifiés dans la méthode OnModelCreating.

⮚ Ajouter la classe Credit dans le projet Domain.

namespace CodeFirst.Domain
{
public class Credit
{
public int CreditId { get; set; }
public float Somme { get; set; }
public DateTime DateCredit { get; set; }
public float TauxInteret { get; set; }
public virtual Compte Comptes { get; set; }
}
}

⮚ Ajouter la propriété de navigation de la liste des crédits dans la classe de l’entité


Compte.

public virtual ICollection<Credit> Credits { get; set; }

⮚ Utiliser les commandes Add-Migration et Update-Database pour mettre à jour la


base de données.

16
EFCore a ajouté la nouvelle table Credit dans la base de données, car il a découvert le type

Credit via la propriété de navigation Compte.Credits.

8. Nom des tables

Par Convention, chaque type d’entité sera configuré pour être mappé à une table de base de
données portant le même nom que la propriété DbSet qui expose l’entité. S’il n’existe aucun
DbSet pour l’entité donnée, le nom de la classe est utilisé.

9. Inclusion de propriété dans le modèle

Chaque type d’entité dans le modèle a un ensemble de propriétés. Dans une base de données
relationnelle, les propriétés d’entité sont mappées à des colonnes de table.
Par Convention, toutes les propriétés publiques avec un accesseur
accesseur get et un accesseur Set seront
incluses dans le modèle.

10. Nom des colonnes

Par Convention, lors de l’utilisation d’une base de données relationnelle, les propriétés d’entité
sont mappées à des colonnes de table portant le même nom que la propriété.

11. Types de données des colonnes

Lors de l’utilisation d’une base de données relationnelle, le fournisseur de base de données


sélectionne un type de données en fonction du type .NET de la propriété. Il prend également en
compte d’autres métadonnées, telles que la longueur maximale configurée, si la propriété fait
partie d’une clé primaire, etc.

Par exemple, SQL Server mappe les DateTime Propriétés aux datetime2(7) colonnes et string
aux propriétés nvarchar(max) des colonnes (ou à nvarchar(450) pour les propriétés utilisées
comme clé).

12. Propriétés obligatoires et facultatives

17
Une propriété est considérée comme facultative si elle est valide pour contenir null . Si null n’est
pas une valeur valide à assigner à une propriété, elle est considérée comme étant une propriété
obligatoire. Lors du mappage à un schéma de base de données relationnelle, les propriétés
requises sont créées en tant que colonnes n’acceptant pas les valeurs NULL, et les propriétés
facultatives sont créées en tant que colonnes Nullable.
Par Convention, une propriété dont le type .NET peut contenir une valeur null sera configurée
comme étant facultative, alors que les propriétés dont le type .NET ne peut pas contenir de valeur
null seront configurées selon les besoins. Par exemple, toutes les propriétés avec des types valeur
.net ( int , decimal , bool , etc.) sont configurées en fonction des besoins, et toutes les propriétés
avec des types valeur .net Nullable ( int? , decimal? ,, bool? etc.) sont configurées comme étant
facultatives.
C# 8 a introduit une nouvelle fonctionnalité appelée types de référence Nullable (Diagnostics
proactifs NRT), qui permet d’annoter des types de référence, indiquant s’il est valide qu’ils
contiennent ou non des valeurs NULL. Cette fonctionnalité est désactivée par défaut et affecte le
comportement de EFCore de la façon suivante :
● Si les types de référence Nullable sont désactivés (valeur par défaut), toutes les
propriétés avec des types de référence .NET sont configurées comme étant
facultatives par convention (par exemple, string ).
● Si les types de référence Nullable sont activés, les propriétés seront configurées en
fonction de la possibilité de valeur null C# de leur type .NET : string? sera
configuré comme étant facultatif, mais string sera configuré comme requis.

13. Configuration d’une clé primaire

Par Convention, une propriété nommée Id ou <type name>Id sera configurée comme clé
primaire d’une entité.
Vous pouvez également configurer plusieurs propriétés comme clé d’une entité. Il s'agit d’une
clé composite.

14. Nom de la clé primaire

18
Par Convention, sur les bases de données relationnelles, les clés primaires sont créées avec le

nom PK_<type name> .


15. Types et valeurs de clé

Si EFCore prend en charge l’utilisation de propriétés de n’importe quel type primitif comme clé
primaire, y compris string , Guid byte[] et d’autres, toutes les bases de données ne prennent pas
en charge tous les types en tant que clés. Dans certains cas, les valeurs de clé peuvent être
converties automatiquement en un type pris en charge ; sinon, la conversion doit être spécifiée
manuellement.

16. Relations

Une relation définit la relation entre deux entités. Dans une base de données relationnelle, elle est
représenteé par une contrainte de clé étrangère.
Par défaut, une relation est créée lorsqu’une propriété de navigation est détectée sur un type. Une
propriété
iété est considérée comme une propriété de navigation si le type vers lequel elle pointe ne
peut pas être mappé en tant que type scalaire par le fournisseur de base de données actuel.
Le modèle le plus courant pour les relations est d’avoir des propriétés de navigation définies aux
deux extrémités de la relation et une propriété de clé étrangère définie dans la classe d’entité
dépendante.
Bien qu’il soit recommandé d’avoir une propriété de clé étrangère définie dans la classe d’entité
dépendante, elle n’est pas obligatoire. Si aucune propriété de clé étrangère n’est trouvée, une
propriété de clé étrangère Shadow est introduite avec le nom <navigation property
name><principal key property name> ou <principal entity name><principal key property name>
si aucune navigation n’est présente sur le type dépendant.

19
L’inclusion
’inclusion d’une seule propriété de navigation (aucune navigation inverse et aucune propriété
de clé étrangère) suffit à avoir une relation définie par Convention. Vous pouvez également avoir

une propriété de navigation unique et une propriété de clé étrangère.


étran
17. Suppression en cascade

Par Convention, la suppression en cascade sera définie sur cascade pour les relations requises et
ClientSetNull pour les relations facultatives. Cascade signifie que les entités dépendantes sont
également supprimées. ClientSetNull
ClientSetNull signifie que les entités dépendantes qui ne sont pas
chargées en mémoire restent inchangées et doivent être supprimées manuellement ou mises à
jour pour pointer vers une entité principale valide. Pour les entités chargées en mémoire, EFCore
tente de définir
éfinir les propriétés de clé étrangère sur la valeur null.

● Annotations
Parfois, les conventions par défaut ne sont pas idéales pour votre modèle, vous devez donc
configurer les entités individuellement en utilisant les annotations ou les configuration
FluentApi.
DataAnnotation est une configuration basée sur un simple attribut,
attribut, on peut l’appliquer sur les
classes et leurs propriétés. Les attributs existent dans les deux namespaces suivants:

● System.ComponentModel.DataAnnotations
● System.ComponentModel.DataAnnotations.Schema

Cependant, DataAnnotation fournit seulement un sous-ensembles


sou ensembles de configurations FluentAPI.
Donc, si certains attributs n’existent pas dans DataAnnotation, alors vous devez utiliser Fluent
API pour configurer vos entités.

20
1. System.ComponentModel.DataAnnotations

Fournit des classes d’attributs utilisées pour définir des métadonnées pour les contrôles de
données ASP.NET et ASP.NET MVC.

Classes:
AssociatedMetadataTypeTypeD Étend les informations de métadonnées pour une classe en
escriptionProvider ajoutant les informations d'attributs et de propriétés
définies dans une classe associée.

AssociationAttribute Spécifie qu'un membre d'entité représente une relation de


données, telle qu'une relation de clé étrangère.

CompareAttribute Fournit un attribut qui compare deux propriétés.

ConcurrencyCheckAttribute Spécifie qu'une propriété participe aux contrôles d'accès


concurrentiel optimiste.

CreditCardAttribute Spécifie qu'une valeur de champ de données est un numéro


de carte bancaire.

CustomValidationAttribute Spécifie une méthode de validation personnalisée qui est


utilisée pour valider une instance de classe ou de propriété.

DataTypeAttribute Spécifie le nom d'un type supplémentaire à associer à un


champ de données.

21
DisplayAttribute Fournit un attribut à usage général qui vous permet de
spécifier les chaînes localisables pour les types et membres
de classes d'entité partielles.

DisplayColumnAttribute Spécifie la colonne qui s'affiche dans la table désignée


comme colonne de clé étrangère.

DisplayFormatAttribute Spécifie la manière dont les champs de données sont


affichés et mis en forme par Dynamic Data ASP.NET.

EditableAttribute Indique si un champ de données est modifiable.

EmailAddressAttribute Valide une adresse de messagerie.

EnumDataTypeAttribute Permet de mapper une énumération .NET avec une


colonne de données.

FileExtensionsAttribute Valide les extensions de nom de fichier.

FilterUIHintAttribute Représente un attribut qui est utilisé pour spécifier le


comportement de filtrage d'une colonne.

KeyAttribute Indique une ou plusieurs propriétés qui identifient une


entité de manière unique.

22
MaxLengthAttribute Spécifie la longueur maximale du tableau ou des données
de type chaîne autorisée dans une propriété.

MetadataTypeAttribute Spécifie la classe de métadonnées à associer à une classe


de modèle de données.

MinLengthAttribute Spécifie la longueur minimale du tableau ou des données


de type chaîne autorisée dans une propriété.

PhoneAttribute Spécifie qu'une valeur de champ de données est un numéro


de téléphone bien formé.

RangeAttribute Spécifie les contraintes de plage numérique pour la valeur


d'un champ de données.

RegularExpressionAttribute Spécifie qu'une valeur de champ de données dans Dynamic


Data ASP.NET doit correspondre à l'expression régulière
spécifiée.

RequiredAttribute Spécifie qu'une valeur de champ de données est


obligatoire.

ScaffoldColumnAttribute Spécifie si une classe ou une colonne de données utilise la


génération de modèles automatique.

23
StringLengthAttribute Spécifie les longueurs minimale et maximale de caractères
autorisées dans un champ de données.

TimestampAttribute Spécifie le type de données de la colonne en tant que


version de ligne.

UIHintAttribute Spécifie le modèle ou le contrôle utilisateur utilisé par


Dynamic Data pour afficher un champ de données.

UrlAttribute Fournit la validation de l'URL.

ValidationAttribute Sert de classe de base pour tous les attributs de validation.

ValidationContext Décrit le contexte dans lequel un contrôle de validation est


exécuté.

ValidationException Représente l'exception qui se produit pendant le validation


d'un champ de données lorsque la classe
ValidationAttribute est utilisée.

ValidationResult Représente un conteneur pour les résultats d'une demande


de validation.

24
Validator Définit une classe d'assistance qui peut être utilisée pour
valider des objets, des propriétés et des méthodes
lorsqu'elle est incluse dans leurs attributs
ValidationAttribute associés.

Interfaces:

IValidatableObject Offre un moyen de valider un objet.

Énumérations:

DataType Représente une énumération des types de données associés


aux paramètres et aux champs de données.

2. System.ComponentModel.DataAnnotations.Schema

Fournit la prise en charge des classes d’attributs utilisées pour définir des métadonnées pour les
contrôles de données ASP.NET et ASP.NET MVC.

Classes:

Représente la colonne de base de données à laquelle une


ColumnAttribute propriété est mappée.

25
Dénote que la classe est un type complexe. Les types
ComplexTypeAttribute complexes sont les propriétés non scalaires des types
d'entités qui permettent d'organiser les propriétés scalaires
au sein des entités. Les types complexes n’ont pas de clés
et ne peuvent pas être gérés par l’Entity Framework, mis à
part l’objet parent.

Spécifie comment la base de données génère des valeurs


DatabaseGeneratedAttribute pour une propriété.

Dénote une propriété utilisée comme une clé étrangère


ForeignKeyAttribute dans une relation.

Spécifie l'inverse d'une propriété de navigation qui


InversePropertyAttribute représente l'autre terminaison de la même relation.

Dénote qu'une propriété ou classe doit être exclue du


NotMappedAttribute mappage de base de données.

Spécifie la table de base de données à laquelle une classe


TableAttribute est mappée.

Énumérations:

Représente le modèle utilisé pour générer des valeurs pour


DatabaseGeneratedOption une propriété dans la base de données.

26
using System.ComponentModel.DataAnnotations;

namespace CodeFirst.Domain
{
public class Agence
{
[Key]
public int AgenceId { get; set; }

[Required(ErrorMessage = "Name is required")]


[StringLength(25, ErrorMessage = "Must be less than 25
caracters")]
public string Nom { get; set; }

[DataType(DataType.ImageUrl)]
public string Image { get; set; }

[Range(0, int.MaxValue)]
public int NombreEmploye { get; set; }

public virtual ICollection<Compte> comptes { get; set; }


}
}

● Configurations API Fluent


L'API Fluent d'EF Core est une autre façon de configurer les classes. L'API Fluent fournit plus
de fonctionnalités pour la configuration que les annotations.

L'API Fluent fournit des méthodes pour configurer divers aspects d’un modèle de données:

● Configuration du modèle
● Configuration des entitées
● Configuration des propriétés

Le tableau suivant liste quelques méthodes importantes pour chaque type de configuration.

27
Configuration du modèle:

Ajoute ou met à jour une annotation sur le modèle. Si une


HasAnnotation annotation avec la clé spécifiée dans annotation existe déjà,
sa valeur est mise à jour.

Effectue la configuration d’un type d’entité donné dans le


Entity modèle. Si le type d’entité n’est pas déjà inclus dans le
modèle, il sera ajouté au modèle.

HasDefaultSchema Configure le schéma par défaut dans lequel les objets de


base de données doivent être créés, si aucun schéma n’est
explicitement configuré.

Configuration des entitées:

Définit les propriétés qui composent la clé primaire pour ce


HasKey type d’entité.

Configure une relation dans laquelle ce type d’entité a une


HasMany collection qui contient des instances de l’autre type dans la
relation.

Configure une relation dans laquelle ce type d’entité a une


HasOne référence qui pointe vers une instance unique de l’autre
type dans la relation.

Exclut ce type d’entité du modèle afin qu’il ne soit pas


Ignore mappé à la base de données. Cette méthode est
généralement utilisée pour supprimer les propriétés et les
navigations du type d’entité qui ont été ajoutées par
Convention.

Configure une relation dans laquelle l’entité cible


OwnsOne appartient à cette entité (ou une partie de celle-ci).

Configure la table à laquelle le type d’entité est mappé lors


ToTable du ciblage d’une base de données relationnelle.

Retourne un objet qui peut être utilisé pour configurer une


Property propriété du type d’entité. S’il n’existe aucune propriété
avec le nom donné, une nouvelle propriété est ajoutée.

28
HasDiscriminator Configure la propriété de discriminateur utilisée pour
identifier le type d’entité.

Configuration des propriétés:

Configure la colonne sur laquelle la propriété est mappée


HasColumnName dans un objet de magasin de type table particulier.

Configure le type de données de la colonne mappée à la


HasColumnType propriété lors du ciblage d’une base de données
relationnelle. Il doit s’agir du nom complet du type,
notamment la précision, l’échelle, la longueur, etc.

HasComputedColumnSql Configure la propriété pour qu’elle soit mappée à une


colonne calculée lors du ciblage d’une base de données
relationnelle.

Configure la valeur par défaut de la colonne à laquelle la


HasDefaultValue propriété est mappée lors du ciblage d’une base de données
relationnelle.

Configure l’expression de valeur par défaut pour la


HasDefaultValueSql colonne mappée à la propriété lors du ciblage d’une base
de données relationnelle.

Définit le champ de stockage à utiliser pour cette propriété.


HasField

Configure la longueur maximale des données qui peuvent


HasMaxLength être stockées dans cette propriété. La longueur maximale
ne peut être définie que sur les propriétés du tableau (y
compris les String Propriétés).

Configure si cette propriété doit avoir une valeur assignée


IsRequired ou null une valeur valide. Une propriété ne peut être
configurée qu’en tant que non requis si elle est basée sur
un type CLR qui peut être assigné null.

29
● Types d’entité détenus
EFCore permet de modéliser des types d'entités qui peuvent uniquement apparaître dans les
propriétés de navigation d’autres types d’entités. Il s’agit de types d’entités détenues. L’entité
contenant un type détenu est son propriétaire.

Les entités détenues sont essentiellement une partie de l’entité propriétaire et ne peuvent pas
exister sans elle.

Les types détenus ne sont pas inclus dans le modèle selon les conventions par défaut de EFCore.

Il y a deux façons pour configurer le type en tant que type détenu:

1. Annoter le type avec l’attribut Owned pour configurer le type en tant que type détenu.
2. Utiliser la OwnsOne méthode dans OnModelCreating. OnModelCreating est une
méthode de la classe context qu’on peut substituer afin de configurer davantage le
modèle qui a été découvert par convention à partir des types d'entités exposés dans les
DbSet.

● Stratégies d’héritage
Par convention, EFCore ne recherche pas automatiquement les types de base ou dérivés.

Cela signifie que si vous souhaitez qu’un type de votre hiérarchie soit mappé, vous devez
spécifier explicitement ce type sur votre modèle. Par exemple, si vous spécifiez uniquement le
type de base d’une hiérarchie, EFCore n’inclura pas tous ses sous-types de manière implicite.

Il y a deux approches différentes pour représenter l’héritage dans EFCore Code-First:

1. Configuration TPH et discriminateur


Par défaut, EFCore mappe l’héritage à l’aide du modèle table par hiérarchie (TPH). TPH utilise
une table unique pour stocker les données de tous les types dans la hiérarchie, et une colonne de
discriminateur est utilisée pour identifier le type représenté par chaque ligne.

2. Configuration TPT
La fonctionnalité table par type (TPT) a été introduite dans EFCore 5.0. Cette approche suggère
une table séparée pour chaque classe de la hiérarchie d'héritage.

● Chargement des données associées


EFCore vous permet d’utiliser les propriétés de navigation dans votre modèle pour charger des
entités associées. Il existe trois modèles communs utilisés pour charger les données associées.

30
1. Le chargement hâtif signifie que les données associées sont chargées à partir de la base
de données dans le cadre de la requête initiale.
2. Le chargement explicite signifie que les données associées sont chargées explicitement
à partir de la base de données à un moment ultérieur.
3. Le chargement différé signifie que les données associées sont chargées de façon
transparente à partir de la base de données lors de l’accès à la propriété de navigation.

Dans ce cours on va se focaliser seulement sur le chargement différé avec des proxies.

Chargement différé avec des proxies

La façon la plus simple d’utiliser le chargement différé est d’installer le package


Microsoft.EntityFrameworkCore.Proxies et de l’activer avec un appel à
UseLazyLoadingProxies. Par exemple :
protected override void OnConfiguring(DbContextOptionsBuilder
optionsBuilder)
=> optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer(myConnectionString);

EF Core active ensuite le chargement différé pour n’importe quelle propriété de navigation qui
peut être substituée, c’est-à-dire qui doit être virtual et sur une classe qui peut être héritée.

Références
[1] https://docs.microsoft.com/en-us/ef/core/
[2] https://www.entityframeworktutorial.net/efcore/entity-framework-core.aspx
[3] https://en.wikipedia.org/wiki/Entity_Framework

31

Vous aimerez peut-être aussi