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