Choisir un outil de mapping objet-relationnel
   par Fabrice Marguerie (http://weblogs.asp.net/fmarguerie)
Difficile d'échapper à l'écriture de code d'accès et de manipulation de données quand on développe une application. Les outils de mapping objet-relationnel se proposent de vous aider. Encore faut-il savoir les choisir...

ue l'on développe une petite ou une grosse application, on a toujours à s'occuper de manipuler des données. Il s'agit d'ailleurs d'une partie critique d'une application. Seulement voilà, ce travail est fastidieux, répétitif, et consomme beaucoup du temps que l'on préférerait passer sur d'autres parties de l'application. Sans oublier que moins le travail est intéressant, plus les risques d'erreurs sont élevés.
Pour résoudre ces problèmes, plusieurs solutions existent, visant à simplifier la création d'une couche d'accès aux données, voire à en automatiser le fonctionnement ou la génération.
Nous nous intéresserons ici à une de ces solutions : les outils de mapping objet-relationnel (O/RM ou object-relational mapping in English).

Le principe du mapping objet-relationnel est de déléguer à des outils la gestion de la persistance, et de travailler au niveau du code avec des objets de données proposant une vue orientée vers le domaine métier, et non des structures de données dans un format calqué sur celui de la base de donnée relationnelle (classe DataSet de .NET). Les outils de mapping mettent en correspondance bidirectionnelle les données situées dans une base de données relationnelle et des objets au niveau du code, en se basant sur une configuration et en exécutant des requêtes SQL (le plus souvent dynamiques) sur la base de données.
Nous ne détaillerons pas ici plus avant les principes et les fonctionnements des outils de mapping. Vous pourrez vous référer aux liens en bas de page pour en savoir plus.
Il ne faut pas oublier par ailleurs que d'autres solutions existent, telles celles basées sur la génération de code. Elles ont toutes leurs avantages et leurs inconvénients, tout comme les outils de mapping eux-mêmes bien sûr. L'outil parfait n'existe pas, où alors il faut qu'on me le montre :-)
Nous n'aborderons pas ici ces autres approches, ce n'est pas le sujet du jour.

En terme d'outils, l'offre est large. Cela concerne .NET aussi bien que Java, même si l'offre pour Java est beaucoup plus en avance pour des raisons historiques. Il y a tout de même aujourd'hui de part et d'autre une quantité impressionnante d'outils ! (cf. Liste d'outils pour .NET à la fin de l'article)
La qualité est-elle toujours au rendez-vous ? Les outils sont-ils adaptés à vos besoins ? Voila bien les questions essentielles.
Le plus important pour choisir le bon outil est avant tout de bien définir les critères qui sont essentiels pour vous. Voilà pourquoi nous tâcherons dans cet article de présenter les critères de sélection d'un outil de mapping objet-relationnel.
Les plates-formes Java/J2EE et .NET sont tellement proches, et les besoins étant les mêmes, les critères peuvent être considérés comme universels.

Critères spécifiques au mapping objet-relationnel

Fonctionnalités de base

  • Tirer parti de l'héritage, pouvoir créer des hiérarchies entre les entités et utiliser le polymorphisme (on fait de l'objet !). Les outils peuvent supporter différentes combinaisons de tables et de classes pour la mise en oeuvre de ces mécanismes.
  • Gérer tout type de relations (1-1, 1-n, n-n)
  • Support des transactions
  • Agrégats (équivalent des SUM, AVG, MIN, MAX, COUNT du SQL)
  • Support de groupes (GROUP BY du SQL)

Avantages pratiques

  • Bases de données supportées. Un des gros avantages des outils de mapping, c'est qu'ils apportent une abstraction par rapport au moteur de base de données, et permettent pour la plupart de changer rapidement de moteur de base de données. Vérifiez donc quelles sont les bases de données supportées par les outils.
  • Langage de requête (OQL - Object Query Language, OPath). On a très fréquemment besoin d'exécuter des requêtes dynamiques, ne serait-ce que pour faire des recherches à base de filtres. Il est important de disposer d'un langage de requête puissant.
  • Support du DataBinding (pour pouvoir relier les objets de données à des composants visuels). A noter que des spécificités existent en Windows Forms.

Flexibilité

  • Personnalisation des requêtes exécutées. On a souvent besoin d'aller plus loin que ce qui est permis par le langage de requête. Dans ce cas, il faut pouvoir fournir des requêtes SQL personnalisées. HQL qui est un des points forts de Hibernate/NHibernate permet de faire cela. On peut également souhaiter qu'un mapping dynamique soit possible sur une requête SQL fournie entièrement par le développeur.
  • Support de tout type de jointures SQL (inner join, outer join)
  • Gestion de la concurrence (support des approches optimiste et pessimiste)
  • Support des types de données spécifiques au moteur de base de données (champs de type compteur - identity/autoincrémenté, GUID)
  • Pouvoir associer à une classe des données provenant de plusieurs tables (jointures, vues). La plupart des outils gère un mapping direct d'une table sur une classe. On a souvent besoin de plus.
  • Pouvoir éclater en plusieurs classes les données d'une table

Assistance, simplicité d'utilisation

  • Outil graphique accompagnateur pour configurer le mapping. Un outil de ce type présente le modèle de données et permet de spécifier les objets à créer ou tout au moins le lien entre les objets et les tables.
  • Génération des classes d'objets de données. Cela permet d'accélerer les développements, mais dans certains cas on préférera faire du mapping sur des classes codées à la main ou générées à partir d'UML par exemple. Vérifiez quels cas supporte les outils.
  • Génération du schéma de base de données. Certains outils ne fonctionnent qu'avec une base générée par eux. Cela peut être une grosse contrainte, surtout si vous devez travailler sur une base de données existante bien sûr ! Sinon, tout dépend si vous êtes expert en base de données, ou si vous ne voulez pas avoir à vous soucier du modèle de données. Si vous avez un DBA qui s'occupe des bases des données, ou que vous préfériez les modéliser vous-même, prenez soin de sélectionner un outil de mapping qui ne requiert pas son propre modèle.

Optimisations, performance, conception

  • Performance globale (bonne implémentation du concept de mapping objet-relationnel)
  • Chargement différé (lazy loading)
    • Pour les données obtenues par les relations
    • Pour certains champs. Quand on veut juste présenter une liste de noms, on ne souhaite pas que tous les champs de la table soient chargés. On peut n'avoir besoin des champs blobs qu'à un moment donné, et les charger à ce moment là.
  • Cache des requêtes générées dynamiquement, pour qu'elles ne soient pas reconstruites à chaque appel
  • Cache de certaines données pour éviter trop d'appels à la source de données
  • Requêtes optimisées (mise à jour uniquement des champs modifiés; détection de cas de figure où le nombre de requêtes exécutées peut être réduit; ...)
  • Gère les références circulaires sans duplication des objets ("compte == compte.Client.Compte")
  • Gestion des mises à jour en cascade. La suppression d'un maître doit pouvoir supprimer les détails associés si souhaité.
  • Mises à jour ou suppressions massives. Dans les cas où l'on souhaite modifier ou supprimer des milliers d'enregistrements d'un coup, il est inenvisageable d'avoir à charger tous les objet en mémoire, alors que par une requête SQL cela se fait très simplement et rapidement (DELETE FROM Client WHERE Solde < 0). Un support de la part de l'outil est souhaitable pour rester dans le monde objet sans recourir au SQL. Hibernate a beaucoup de mal sur ce point par exemple.

Evolutivité, ouverture, compatibilité

  • Maintenabilité (que se passe-t'il si le modèle de données change ? Si je dois ajouter une nouvelle collection ?)
  • Possibilité de passer à un autre outil (dans quelle mesure ? A quel coût ?)
  • Sérialisation. La sérialisation peut permettre de sauvegarder des données en dehors de la base de données. La sérialisation peut se faire en binaire, mais aussi surtout en XML (cf. section sur SOA ci-dessous).
  • Objets distribués (remoting, services web, requiert le support de la sérialisation)

Petits plus appréciables

  • Liberté dans les classes (pas de classe de base pour les entités; pas d'interface obligatoire; pas de classe spécifique pour les collections)
  • Le moins de contraintes possible sur le schéma de base de données (support des clefs composites, par exemple)
  • Etat sur les données. Il peut être utile de savoir en consultant un objet si une entité a été ajoutée, modifiée, supprimée.
  • Fichier externe de mapping ou non ? Attributs dans le code ou non ?
    • Avantages d'un fichier externe : mapping complétement externalisé; pas d'intrusion dans les classes; peut être généré
    • Inconvénients d'un fichier externe : un ou plusieurs fichiers supplémentaires à manipuler; syntaxe à connaître si pas d'outil; faire le rapprochement entre le code et la base de données demande une petite gymnastique; possibilité de désynchronisation avec le code
    • Avantages des attributs : tout sous la main au niveau du code; le mapping devient évident puisque présent directement sur les classes et les propriétés; peuvent permettre de générer des fichiers externes par réflexion si nécessaire; si on n'utilise plus l'outil les attributs sont ignorés
    • Inconvénients des attributs : le code est "pollué"; les objets de données référencent un framework de mapping spécifique
  • Compatibilité avec les DataSets de .NET. Il peut être utile de pouvoir convertir une grappe d'objets en DataSet pour s'interfacer avec des composants qui les requièrent (outils de reporting par exemple).
  • Support du mode déconnecté (alimenter des objets depuis la base de données, fermer la connexion, la session, créer/modifier/supprimer des objets, et appliquer ces modifications sur la base de données plus tard)
  • Système d'intercepteurs et mécanismes de délégation pour avoir la main au moment où la gestion de la persistance intervient (pour tracer ce qui se passe par exemple)
  • Support des procédures stockées. Les avantages des procédures par rapport aux requêtes SQL font l'objet d'un grand débat, mais il est préférable d'avoir le choix.
  • Un avantage de certains outils pour .NET peut être leur popularité dans le monde Java. Seul NHibernate est concerné à ce jour. Il s'agit d'une adaptation de Hibernate, outil largement répandu dans le monde Java, qui bénéficie donc d'une bonne documentation et d'une large communauté de développeurs.
  • Possibilité de spécifier des contraintes entre les objets et sur les propriétés (OCL - Object Constraint Language). Cela permet d'éviter d'attendre que les données atteignent la base avant qu'elles ne soient validées.
  • Filtrage d'objets en mémoire (sans que de nouvelles requêtes soient faites sur la base de données)
  • Pouvoir différer les mises à jour de la base de données, et les déclencher à un instant donné par un appel de méthode spécifique, plutôt qu'elles ne soient faites systèmatiquement sur le champ.

Critères non spécifiques

De nombreux critères sont communs à toute sélection de logiciel, et sont donc à inclure dans votre checklist :

  • Prix
  • Performance
  • Consommation en ressources (mémoire)
  • Montée en charge
  • Complexité (ou simplicité...)
  • Rapidité de mise en oeuvre
  • Flexibilité
  • Documentation. L'utilisation d'un outil de mapping ne va pas toujours de soi. Vérifiez bien la qualité de la documentation et des exemples fournis.
  • Maturité. Les outils sont tout neufs, en tout cas pour .NET, et ne sont pas encore arrivés à maturité. Certains n'en sont encore qu'au stade de bêta voire d'alpha.
  • Mises à jour fréquentes du produit, évolutions, correction des bugs
  • Support, forums, communauté
  • Pérennité. C'est un gros problème aujourd'hui. Il y a beaucoup d'outils, la sélection naturelle fera son oeuvre. Quels produits seront encore présents demain ? Certains sont déjà tombés. Le temps et la concurrence continueront probablement à éliminer des acteurs de ce marché très concurrentiel.
  • Source fourni ou non (lié à la perennité)
  • Support de plusieurs plates-formes (Java et .NET ? Windows et Linux ? Framework .NET et Mono ?)

Cas spécifique d'une architecture SOA

Une attention toute particulière doit être portée à certains critères relativement aux architectures orientées services.

Les outils de mapping objet-relationnel basent souvent vos développements sur le principe que les entités que vous manipulez sont liées à une source de données dans laquelle il viennent s'inscrire eux-mêmes lorsqu'ils subissent des modifications. En SOA, la responsabilité de la persistance est déléguée à une couche particulière, le code de persistance ne se trouve pas dans l'entité elle-même.

Vous vous poserez en particulier les questions suivantes :

  • Est-ce que mes objets de données peuvent être sérialisés en XML ?
  • Puis-je enregistrer mes objets de données vers différents formats ?
  • Est-ce que je maîtrise les appels qui sont faits pour la persistance ? Ces appels sont-ils fréquents ? Les moments où ils surviennent sont-ils bien définis ?
  • Puis-je exploiter mes objets de données depuis une autre plate-forme ? Sans l'outil de mapping objet-relationnel ?
  • Est-ce que mes objets métiers n'appelleraient pas directement la base de données depuis la couche de présentation, par hasard ?
  • Que se passe-t'il si je place ma couche de présentation ou les clients de mon service à distance ?

Autres outils

Les outils de mapping ne sont pas la seule solution pour gérer la persistance. La seconde grande catégorie d'outils est constituée par les générateurs de code.
Pour faire simple, les principales différences entre ces deux catégories d'outils peuvent être les suivantes :

  • Les requêtes dynamiques (filtres) ne sont gérés que par les outils de mapping
  • Les outils de mapping mettent en oeuvre la réflexion, ce qui est moins performant que le code compilé obtenu par les générateurs de code

Les outils de génération de code sont nombreux :

Dans certains cas, un outil de génération de code sera plus adapté, dans d'autres un outil de mapping sera préférable. Il est intéressant de noter que certains outils combinent la géneration de code et les techniques de mapping objet-relationnel pour offrir le meilleur des deux mondes.

Post-scriptum

Vous pouvez le voir, les critères sont nombreux ! Il faut donc commencer par déterminer lesquels sont critiques pour vous (les MUST HAVE), lesquels sont secondaires (les NICE TO HAVE).

A vous de vous faire votre opinion. Comme pour tout outil, n'hésitez pas à tester. Téléchargez les versions d'évaluation et utilisez les sur un prototype dans votre domaine d'application.
Jaugez, comparez, utilisez, et critiquez pour que nous aussi nous sachions ce que vous pensez des divers outils...


Qui est Fabrice Marguerie ?
Fabrice Marguerie est architecte .NET chez Alti/Masterline. Fabrice intervient sur des missions de conseil, de conception ou de réalisation. Il a conçu et réalisé le framework .NET de Masterline.
Fabrice rédige un weblog en anglais : http://weblogs.asp.net/fmarguerie et gère le site http://SharpToolbox.com

Sa société : Alti/Masterline
Créée en 1989, Masterline est une SSII qui développe son expertise autour de trois marchés : business intelligence, e-business, SAP. L'accompagnement de Masterline prend la forme de prestations de conseil en technologies, d'ingénierie et services, et d'externalisation, conçues et conduites avec pour objectif premier la création de valeur pour le client. Masterline développe ses expertises (.NET, Java, objet et UML, etc.) au sein de centres de compétences dédiés. Masterline est partenaire Microsoft depuis 1994.
Depuis novembre 2004, Masterline est intégrée à la société Alti.


Ressources