Académique Documents
Professionnel Documents
Culture Documents
Architecture des SI I
Introduction 2
Historique 3
Architecture 4
Fonctionnalités 5
Approches 5
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.
● 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:
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+.
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.
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:
EF Core 3.1 (LTS) Décembre 2019 3 Decembre 2022 .NET Standard 2.0
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:
Approches
Il existe deux approches de l’EF Core : Code First et 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.
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.
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).
EF Core ne fait pas partie de .NET Core. Il est disponible sous forme 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.
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; }
}
}
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.
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.
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.
Afin de pouvoir utiliser les migrations on doit installer les deux packages NuGet suivants:
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.
10
⮚ Donner un nom à la migration (exemple: FirstMigration)
11
Après avoir créé une migration, on va générer la base de données à l'aide de la commande Update-
Database
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; }
}
}
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.
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.
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
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.
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.
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.
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.
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é.
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.
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é.
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é).
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.
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.
17
Par Convention, sur les bases de données relationnelles, les clés primaires sont créées avec le nom
PK_<type name> .
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.
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
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.
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.
21
MaxLengthAttribute Spécifie la longueur maximale du tableau ou des données
de type chaîne autorisée dans une propriété.
22
StringLengthAttribute Spécifie les longueurs minimale et maximale de caractères
autorisées dans un champ de données.
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:
Énumérations:
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:
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.
Énumérations:
25
using System.ComponentModel.DataAnnotations;
namespace CodeFirst.Domain
{
public class Agence
{
[Key]
public int AgenceId { get; set; }
[DataType(DataType.ImageUrl)]
public string Image { get; set; }
[Range(0, int.MaxValue)]
public int NombreEmploye { get; set; }
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:
27
HasDiscriminator Configure la propriété de discriminateur utilisée pour
identifier le type d’entité.
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.
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.
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.
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.
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