Vous êtes sur la page 1sur 30

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 7
Implémentation du context dans le projet Data 8
Migrations 10
Conventions par défaut 15
Annotations 19
Types d’entités détenus 27
Stratégies d’héritage 27
Chargement des données associées 28

Références 29

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 qu’un ORM?


ORM (object-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 des classes

● 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 avec la base de données, comme
illustré ci-dessous:

Qu'est-ce que Entity Framework Core?


Entity Framework Core (EF Core), 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.

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

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

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

Comme le montre la figure, EF Core fait partie de la couche Data. Il s'insère entre les classes de
domaine et la base 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 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 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 6 (EF Core 6), publiée le 10 novembre
2021.

Bien que Entity Framework 6.x (EF 6.x) soit toujours pris en charge, il n’est plus développé et ne
reçoit que des correctifs pour les problèmes de sécurité. Le codebase EF 6.x est très stable et il est

3
prioritaire de préserver cette stabilité en n’apportant aucune modification inutile au code. Il est
fortement encouragé que les nouvelles applications et les applications existantes qui sont en
développement actif utilisent Entity Framework Core (EF Core).

Le tableau suivant illustre les dates de sortie des différentes versions de EF Core:

Version de EF Core Date de sortie Date Expiration Framework Cible

EF Core 1.0 Juin 2016 27 Juin 2019 .NET Standard 1.3

EF Core 1.1 Novembre 2016 27 Juin 2019 .NET Standard 1.3

EF Core 2.0 Août 2016 1 Octobre 2018 .NET Standard 2.0

EF Core 3.0 Septembre 2019 3 Mars 2020 .NET Standard 2.1

EF Core 3.1 (LTS) Décembre 2019 3 Decembre 2022 .NET Standard 2.0

EF Core 5.0 Novembre 2020 10 Mai 2022 .NET Standard 2.1

EF Core 6.0 (LTS) Novembre 2021 8 Novembre 2024 .NET 6

EF Core 7.0 Novembre 2022 - .NET 7


(estimée)

Architecture
La figure suivante montre l'architecture globale de EF Core pour l’accès aux données:

4
● 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.
3. Mappage: 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 Services: 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 EF Core 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’EF Core : Code First et Database First

● Approche Database First

5
Si vous avez déjà une base de données, EF Core permet de générer automatiquement le contexte
et les entités qui correspondent aux tables de la base de données existantes à l'aide de l'assistant
EDM intégré à Visual Studio ou en exécutant des commandes EF.

● 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 Core, sans fichier.
Edmx. EF Core 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 EF Core 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 (AM.Infrastructure et AM.Core.Domain) et un projet de type
application console (AM.UI.Console).

➢ Ajouter les références entre les différents projets:


● Le projet Console se référencie au projet Infrastructure.
● Le projet Infrastructure se référencie au projet ApplicationCore.

EF Core 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 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; }
}
}

● Implémentation du context dans le projet Infrastructure


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’EF Core. 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.

8
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. EF Core 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.

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()
{

9
}
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

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

● 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.

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

10
⮚ 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: 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()
qui contient des instructions pour la création et une autre méthode Down() pour la
suppression.

11
Après avoir créé une migration, 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.

EF Core CodeFirst a créé la base de données avec le nom et l'emplacement spécifiés dans la chaîne
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 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

EF Core 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 Core 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 Core 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.

● Conventions par défaut


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

6. 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; }
}
}

15
⮚ 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.

EF Core 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.

7. 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é.

8. 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 get et un accesseur Set seront
incluses dans le modèle.

9. 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é.

10. 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.

16
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é).

11. Propriétés obligatoires et facultatives

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 EF Core 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.

12. 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.

13. Nom de la clé primaire

17
Par Convention, sur les bases de données relationnelles, les clés primaires sont créées avec le nom
PK_<type name> .

14. Types et valeurs de clé

Si EF Core 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.

15. 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é 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.

18
L’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.

16. 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 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, EF Core tente de
dé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, 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 de configurations FluentAPI.


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

1. System.ComponentModel.DataAnnotations

19
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.

20
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.

21
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.

22
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.

23
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.

24
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 dans


ForeignKeyAttribute 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.

25
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.

26
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 appartient


OwnsOne à 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.

27
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 colonne


HasDefaultValueSql 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.

28
● Types d’entités détenus
EF Core 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 EF Core.

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, EF Core 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, EF Core 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 EF Core Code-First:

1. Configuration TPH et discriminateur


Par défaut, EF Core 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 EF Core 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


EF Core 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.

29
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

30

Vous aimerez peut-être aussi