Logiciel
20.08.2024 13:34

Partager avec d'autres :

Partager

Mappage objet-relationnel avec Entity Framework

Aujourd'hui, le World Wide Web est le service le plus populaire du plus grand réseau informatique, Internet. Plus de 100 000 nouvelles pages Web le rejoignent chaque jour, allant des pages statiques avec un support d'interaction minimal aux pages dynamiques qui nécessitent une grande quantité de données à jour pour remplir leurs fonctions.
La photo est illustrative. (Photo : Pixabay)
La photo est illustrative. (Photo : Pixabay)

Auteurs : Denis Balant, Enej Hudobreznik


Malgré le développement rapide de la technologie, le principal langage de gestion des bases de données relationnelles reste SQL. langage de requête structuré, qui, avec de nombreux dérivés personnalisés (PostgreSQL, MySQL...), trouve ses racines dans les années 70 du siècle dernier.

L'écriture de requêtes SQL s'avère souvent un travail assez fastidieux, en particulier avec des structures de bases de données plus complexes. Au lieu d'écrire manuellement des requêtes et des conversions vers des objets typiques des langages de programmation orientés objet, il est beaucoup plus naturel et souvent plus simple de mapper les classes du code source au schéma de données et non l'inverse. Cela permet de gagner du temps de développement et, en même temps, de reconnaître beaucoup plus facilement les relations entre les entités. Cette méthode est appelée mappage objet-relationnel (ORM).

Pour l'environnement .NET, Microsoft propose à cet effet le framework open source Entity Framework Core (EF Core en abrégé), qui permet un développement orienté données (l'approche Code First), où les données interconnectées sont simplement collectées dans des classes qui représentent des tables, et le framework est basé sur ces bases, il comprend les relations et crée un schéma de base de données dans son propre format. Le plus grand avantage d’une telle approche est la possibilité d’installer le schéma de données sur la base de données souhaitée sans connaître SQL.

EF Core communique avec les bases de données via des bibliothèques de plug-ins appelées fournisseurs de bases de données, ce qui facilite le passage à une autre base de données. Ceux-ci peuvent être installés par l'utilisateur via le gestionnaire de packages (NuGet pour C#). Les bibliothèques officielles ne sont disponibles que pour les solutions Microsoft SQL Server et Azure Cosmos DB et le projet SQLite, et grâce à la forte communauté open source, le framework supporte pratiquement toutes les principales bases de données relationnelles (MySQL, PostgreSQL...).

A titre d'exemple de modélisation de données, jetons un œil à la table « Étudiant », qui possède les attributs prénom (chaîne de vingt caractères maximum), nom (chaîne de vingt caractères maximum) et identifiant unique (entier).

Tableau Étudiant (propre source)

Dans PostgreSQL, nous définissons cette table comme suit :

Définition de la table des étudiants dans PostgreSQL (propre source)

En plus des définitions des types de base pour le prénom et le nom, nous exigeons également qu'ils ne soient jamais vides (NOT NULL). Le type SERIAL représente un entier unique, qui dans notre cas sert de clé primaire de l'Id. Pour chaque entité ajoutée, elle est automatiquement déterminée en fonction de l'ID de l'identité précédemment ajoutée, qui est simplement incrémentée.

Cependant, il est beaucoup plus simple de définir la table en tant que classe dans le code source de la logique de l'application à l'aide d'un ORM qui crée lui-même l'objet et les exigences de base de données correspondantes. La balise Key au-dessus de l'attribut class indique la clé primaire et Required indique que l'attribut ne doit pas être vide.

Après développement, le framework EF Core nous permet de générer automatiquement un schéma de données à partir du code et de le déployer dans la base de données sélectionnée via les outils de ligne de commande inclus dans le framework. Les modifications progressives du schéma de la base de données sont gérées via ces migrations, qui garantissent que la base de données reste synchronisée avec le modèle de données de l'application. Les nouvelles migrations, stockées dans EF Core sous la forme de classes spéciales, sont créées en comparant le modèle de données actuel avec le schéma de base de données actuel (état de la dernière migration).

Définition de la table des étudiants à l'aide d'EF Core dans un environnement .NET (propre source)

La connexion à la base de données est abstraite par une classe qui hérite de la classe DbContext. Ses attributs sont des collections d'entités de type DbSet qui correspondent à des tables.

Classe de connexion à la base de données et table étudiant définies (propre source)

Le cadre d'écriture de requêtes susmentionné utilise la syntaxe LINQ, qui représente une manière unifiée de récupérer et de traiter des données provenant de différentes sources. La requête est ensuite traduite en SQL et le résultat lui-même est retraduit en un objet, son attribut ou une table d'objets.

L'exemple ci-dessous montre une requête pour un étudiant avec un numéro d'inscription connu. Il suffit d'un seul appel à la méthode Find avec la valeur de la clé primaire (ID).

Exemple de requête d'étudiant avec EF Core (propre source)

Si nous voulons obtenir le même résultat sans utiliser d’outil ORM, cela nécessite beaucoup plus de code. Un exemple utilisant la bibliothèque NpgSql est présenté. Tout d'abord, nous devons créer des objets qui représentent la requête SQL et lire la base de données, tout en faisant attention à inclure correctement le paramètre pour éviter d'éventuelles vulnérabilités, telles que par ex. Injection SQL. Cette fois, nous devons créer nous-mêmes l'objet étudiant, mais nous devons faire attention à l'ordre des attributs dans la requête et à la possibilité d'une erreur dans la requête.

Exemple de requête d'étudiant utilisant la bibliothèque NpgSql (propre source)
Réponse à la requête ci-dessus (propre source)

Le mappage objet-relationnel nous offre ainsi une couche d'abstraction qui accélère considérablement le développement logiciel grâce à son mappage à partir d'un plan de développement orienté objet, car le code SQL n'a pas besoin d'être écrit séparément du code source (souvent orienté objet), un ORM bien écrit prend en charge de bons modèles et pratiques de développement pour la conception d'applications, tout en permettant aux développeurs non SQL d'intégrer plus facilement une base de données relationnelle dans leur application.

Cependant, il est important de souligner que l’ORM n’est pas une solution parfaite. La faiblesse réside précisément dans l’abstraction qu’elle nous propose. Il génère beaucoup plus de code SQL qu'un développeur n'en écrirait, ce qui peut grandement affecter la vitesse des applications, masquer de mauvaises pratiques d'accès aux bases de données et constituer un problème de compatibilité ascendante. Bien que le code généré soit correct dans la plupart des cas, il est néanmoins recommandé de le vérifier et de le tester manuellement.

Le mappage relationnel d'objets est une fonctionnalité qui n'est pas native de l'environnement .NET. La fonctionnalité est fournie par la plupart des frameworks et bibliothèques pour différents langages. Des exemples sont Django pour Python, Gorm pour Go, Spring pour Java, Prisma pour JavaScript (ou Node.js)...




Que lisent les autres ?