«Table Per Concrete Type » avec Entity Framework Core 7

Dans cet article, nous allons voir la nouvelle stratégie de gestion d’un modèle de données ayant une hiérarchie avec Entity Framework Core : la stratégie « Table par type Concret » (TPC – Table Per Concrete type). Bien que ce dernier supporte déjà la stratégie « Table par hiérarchie » (TPH – Table Per Hierarchy) et la stratégie « Table par type » (TPT – Table Per Type), nous verrons les différences fondamentales du TPC sur les autres stratégies.
A quoi servent les stratégies TPH, TPT ou TPC ?
En orienté objet, il n’est pas rare d’utiliser une structure hiérarchique (l’héritage) pour modéliser un système. Elle permet de spécialiser la caractéristique d’une information au travers des classes enfants tout en permettant, une abstraction plus ou moins grande par le biais des classes parentes.
Vous noterez que dans notre abstraction, la notion de Client se suffit à elle-même, c’est une entité feuille, contrairement à Employé qui est un autre niveau hiérarchique intermédiaire (entité branche).
Ce type de représentation d’un système est commun en langage orienté objet mais pas en SQL.
En TPH, toute la hiérarchie est représentée dans une seule et unique table. Les colonnes qui ne correspondent pas à une entité feuille sont initialisées à NULL.
Voyons ensemble comment cette dernière est représentée en SQL via Entity Framework Core 7.
Mise en contexte
Pour notre modèle, nous allons prendre un exemple simple de gestion de personnel et de visiteurs d’une entreprise.
Dans notre modèle, nous avons :
- 2 entités branches: Person et Employee
- 3 entités feuilles : Customer, Technician et Manager
- Une liaison « many to many » entre Customer et BusinessManager
Ci-dessous, le code relatif à notre modèle est le suivant :
Ce modèle est défini dans un projet dont la configuration est la suivante :
Les dépendances dont nous avons besoin sont :
- EntityFrameworkCore : pour l’utilisation du contexte de base de données et la mise en place de la configuration associé
- EntityFrameworkCore.SqlServer : pour définir le type de stratégie de représentation de notre modèle en base de données et interagir avec notre base SQL Server
- EntityFrameworkCore.Design : pour créer et appliquer les migrations de notre modèle à notre base pour la mise en place du code first
Notre contexte basique est défini comme suit :
Une configuration est présente pour chaque classe de notre modèle. Cela nous permettra de manipuler le niveau d’abstraction que nous souhaitons. Deux spécificités sont à noter : la première est la définition d’une séquence pour laisser la gestion du numéro d’employé (EmployeeId) à la base et la seconde est la définition de la liaison « many to many » entre les entités BusinessManager et le Custormer.
A ce point de la configuration, Entity Frameword va sélectionner par défaut la stratégie TPH (Table Per Hierarchy) pour représenter notre modèle de base. Pour choisir, la stratégie TPC (Table Per Concrete type), il nous suffit d’ajouter dans la méthode OnModelCreating le code suivant :
L’équivalent pour le TPH et le TPT est défini ainsi :
On peut noter que seules les entités feuilles de notre modèle ont une table qui leur est associée. Les entités « Person » et « Employee » ne sont pas représentées, contrairement à la stratégie TPT où ces dernières ont une table qui leur ait associée. Cela est dû au fait que C# n’autorise pas d’instance d’une classe abstraite. Cela rentre en contradiction avec le concept de « Concret Type » dans le TPC.
Les tables ne contiennent que les informations de leur entité respective, ainsi il y a répétition des informations relatives aux entités branches. La colonne « EmployeeId » est présente dans les tables « Technicians » et « BusinessManagers ».
NB : pour pouvoir appliquer les changes sur notre base, vous devrez probablement mettre à jour votre outil EF Core CLI avec la commande suivante :
dotnet tool update --global dotnet-ef
Mais comment exploiter notre modèle avec cette représentation de notre base de données ?
Les requêtes SQL TPC
TPC génère des requêtes qui privilégient l’utilisation de « UNION ALL » par rapport au « JOIN ». Bien que les requêtes soient un peu plus longues à écrire, elles sont plus performantes que le TPT.
Ici, nous requêtons l’ensemble de la hiérarchie. Les propriétés ne faisant pas partie des tables sont définies dans la requête comme étant « NULL » par EF Core. C’est le cas de :
- « EmployeeId » et « Expertise » pour le « Customer »
- « CompanyName » et « Expertise » pour le « BusinessManager »
- « CompanyName » pour le « Technician »
Le discriminateur est le mécanisme qui, permettant d’identifier l’entité feuille de notre hiérarchie, est mappé sur le nom de l’entité directement dans la requête. Celui-ci n’est pas persisté dans la base de données. Ainsi, le requêtages des entités branches de la hiérarchie revient à requêter chaque entité feuille de la hiérarchie puis à réunir l’ensemble des résultats grâce au « UNION ALL ».
EF Core utilise par défaut la stratégie TPH, cette dernière étant la plus performante des trois pour le requêtage de l’ensemble de la hiérarchie, puis toutes les entités sont stockées dans la même table.
L’exemple ci-dessous nous montre une requête pour avoir tous les employés :
Là où le TPC se distingue par rapport au TPT, c’est sur le requêtages des entités feuilles qui se fait directement via table associé à l’entité, là où le TPT nécessite de faire des jointures entre plusieurs tables.
La suppression et la mise à jour des données se font directement dans la table concernée.
L’essentiel à retenir
La mise en place de la stratégie TPC avec Entity Frameword Core 7 est aussi simple que celle des stratégies TPH (par défaut) et TPT.
La structure de données qui en découle est calquée sur tous les types concrets de votre hiérarchie. Le requêtage de toute la hiérarchie en est complexifié par le biais des « UNION ALL », mais grandement simplifié sur le requêtage des entités feuilles de la hiérarchie par rapport à la stratégie TPT.
Vous trouverez le code source de cet article ici.
Et pour en savoir plus sur les dernières nouveautés de .NET 7, n’hésitez pas à consulter les autres articles de cette série :
- Découvrez les nouveautés de C#11
- Reprendre la main sur la gestion des caches avec “Output Caching” et .Net 7
- Minimal API dans ASP.NET Core
- Nouveauté d’ASP.NET Core 7 : le middleware Rate Limiting
Vous souhaitez être accompagné dans vos projets IT ou échanger avec nos experts ? Contactez-nous !
Sources :