Concepts : Bases
de données relationnelles et orientation objet
Rubriques
Introduction
Ce document présente des modèles d'objet et de données
relationnels et fournit une description abrégée d'une structure de persistance.
Bases de
données relationnelles et orientation objet
Les bases de données relationnelles et l'orientation objet ne sont pas
entièrement compatibles. Elles représentent deux vues différentes du monde :
dans un SGBDR, tout ce que vous voyez, ce sont des données ; dans un système
orienté objet, seul le comportement est visible.
Ce n'est pas qu'une perspective soit meilleure que l'autre : le modèle orienté
objet tend à bien fonctionner pour des systèmes ayant un comportement complexe
et spécifique à l'état dans lesquels les données sont secondaires, ou dans des
systèmes dans lesquels les données sont accédées par navigation uniquement
selon une hiérarchie naturelle (par exemple, des nomenclatures). Le modèle
SGBDR est parfaitement adapté aux applications générant des rapports et aux
systèmes dans lesquels les relations sont dynamiques ou ad-hoc.
Le problème qui se pose est que de nombreuses informations sont stockées
dans des bases de données relationnelles et si des applications orientées objet
souhaitent accéder à ces données, elles doivent pouvoir lire et écrire dans un SGBDR.
En outre, les systèmes orientés objet nécessitent souvent de partager des
données avec des systèmes non orientés objet. Il est naturel, de ce
fait, d'utiliser un SGBDR comme mécanisme de partage.
Alors que les conceptions relationnelles et orientées objet partagent des
caractéristiques communes (un attribut d'objet est par conception similaire à
des colonnes d'entités), les différences fondamentales font un défi de
l'intégration parfaite. La principale différence réside dans le fait que les
modèles de données exposent les données (via des valeurs de colonne) tandis que
les modèles d'objet les masquent (les encapsulant derrière ses interfaces
publiques).
Le modèle relationnel est composé d'entités et de relations. Une entité peut
être une table physique ou une projection logiques de plusieurs tables,
appelées également vue. La figure ci-dessous illustre les tables LINEITEM,
ORDER et PRODUCT, ainsi que leurs différentes relations. Un modèle relationnel
présente les éléments suivants :

Modèle relationnel
Une entité comporte des colonnes. Chaque colonne est identifiée par un
nom et un type. Dans la figure ci-dessus, l'entité LINEITEM est composée
des colonnes LineItem_Id (la clé primaire), Description, Price, Quantity,
Product_Id et Order_Id (les deux dernières sont les clés externes qui relient
l'entité LINEITEM aux entités ORDER et PRODUCT).
Une entité comporte des enregistrements ou des lignes. Chaque ligne
représente un ensemble unique d'informations qui représente de manière unique
les données persistantes d'un objet.
Chaque entité présente une ou plusieurs clés primaires. Elles identifient de
manière unique chaque enregistrement (par exemple, l'Id est la clé primaire de
la table LINEITEM).
La prise en charge des relations est spécifique au fournisseur. L'exemple
illustre le modèle logique et les relations entre les tables PRODUCT et LINEITEM. Dans
le modèle physique, les relations sont typiquement implémentées à l'aide de
références de clé externe/clé primaire. Si une entité fait référence à une
autre, elle contient des colonnes qui sont des clés externes.
Les colonnes de clé externe contiennent des données qui peuvent associer
des enregistrements spécifiques de l'entité à l'entité associée.
Les relations présentent une multiplicité (également connue en tant que
cardinalité). Les cardinalités courantes sont 1 à 1, 1 à n, n à 1 et n à n.
Dans l'exemple, LINEITEM présente une relation 1 à 1 avec PRODUCT et PRODUCT
une relation 0 à n avec LINEITEM.
Un modèle Objet contient, entre autres choses, des classes (voir [UML01]
pour une complète définition d'un modèle d'objet). Les classes définissent
la structure et le comportement d'un ensemble d'objets, parfois appelés
instances d'objet.
La structure est représentée sous forme d'attributs (valeurs de données) et d'associations
(relations entre classes). La figure suivante illustre un diagramme de
classe simple, ne présentant que les attributs (données) des classes.

Modèle Objet (diagramme de classes)
Une commande porte un numéro (le numéro de commande) et une association à 1
ou plusieurs (1..*) lignes article. Chaque ligne article présente une
quantité (la quantité commandée).
Le modèle d'objet prend en charge l'héritage. Une classe peut hériter des
données et du comportement d'une autre classe (par exemple, des produits
SoftwareProduct et HardwareProduct héritent d'attributs et de méthodes de la
classe Product).
La majorité des applications métier utilisent une technologie relationnelle
comme magasin de données physiques. Le défi auquel font face les développeurs
d'applications orientées objet est de séparer suffisamment et d'encapsuler la
base de données relationnelle de telle sorte que les modifications du modèle de
base ne "brisent" pas le modèle objet, et vice versa. De
nombreuses solutions existent qui permettent aux applications d'accéder
directement aux données relationnelles. Le défi consiste alors à parvenir à
une intégration transparente entre le modèle objet et le modèle de données.
Les interfaces de programmation d'application (API) de base de données
existent dans des versions standard (telle que ODBC de Microsoft) ou sont
propriétaires (liaisons natives à des bases de données spécifiques).
Les API fournissent des services d'application en langage LMD qui permettent
aux applications d'accéder aux données relationnelles brutes.
Dans des applications orientées objet, les données doivent subir une
translation relationnelle objet pour pouvoir être utilisées par l'application. Ceci
nécessite qu'une quantité considérable du code d'application effectue une
translation des résultats de l'API de la base de données brute en objets
d'application. Le but de la structure relationnelle objet est d'encapsuler de
manière générique le magasin de données physiques et de fournir des services de
translation d'objets appropriés.

Objectif d'une structure de persistance
Les développeurs d'applications passent plus de 30% de leur temps à mettre
en oeuvre l'accès aux bases de données relationnelles dans des applications orientées objet.
Si l'interface relationnelle objet n'est pas correctement mise en oeuvre,
l'investissement est perdu. L'implémentation d'une structure
relationnelle objet capture cet investissement. La structure relationnelle
objet peut être réutilisée dans les applications ultérieures, réduisant le
coût d'implémentation relationnel objet à moins de 10% des coûts
d'implémentation globaux.
Le coût le plus important à prendre en considération lors de l'implémentation
d'un système est la maintenance. Plus de 60% des coûts totaux d'un
système au cours de son cycle de vie complet peuvent être attribués à la maintenance. Un
système relationnel faiblement mis en oeuvre est une charge de maintenance à la
fois technique et financière.
- Performances. Une attention particulière doit être
portée à la décomposition des objets en données et à la composition des objets
à partir de données. Dans les systèmes où le rendement des données est élevé
et constitue un point sensible, c'est souvent le talon d'Achille d'une d'accès
conçue de manière inappropriée.
- Réduire les compromis de conception. Un pattern familier
pour les technologistes objet ayant créés des systèmes qui utilisent des bases
de données relationnelles, consiste à affiner le modèle Objet pour faciliter le
stockage dans des systèmes relationnels et de modifier le modèle relationnel
pour faciliter le stockage des objets. Alors que des réglages mineurs sont
souvent nécessaires, une couche d'accès parfaitement conçue réduit la
détérioration de la conception du modèle relationnel et objet.
- Extensibilité. La couche d'accès est une structure qui
permet aux développeurs d'applications d'étendre la structure si certaines
fonctionnalités y sont souhaitées. En général, une couche d'accès
prend en charge, sans extension, 65 à 85% des exigences de stockage des
données d'une application. Si la couche d'accès n'est pas conçue comme une
structure extensible, répondre aux derniers 35 à 15% des exigences de stockage
des données d'une application peut s'avérer très difficile et onéreux.
- Documentation. La couche d'accès est à la fois un
composant fonctionnel et structurel. L'API d'un composant fonctionnel doit
être clairement définie, parfaitement documentée, et facilement compréhensible.
Comme précédemment indiqué, la couche d'accès est conçue pour être étendue.
Une structure extensible doit être très détaillée. Les classes destinées à
être surclassées doivent être identifiées. Les caractéristiques du protocole de
chaque classe concernée doivent être spécifiées (par exemple, publique,
privée, protégée, finale, etc.). En outre, une partie importante de la
conception de la structure en couches d'accès peut être exposée et documentée
pour faciliter l'extensibilité.
- Prise en charge des mappages relationnels objet courants. Une
couche d'accès doit fournir la prise en charge de certains mappages relationnels objet
de base sans le besoin d'extension. Ces mappages relationnels objet sont
présentés dans une section ultérieure de ce document.
- Interfaces de persistance. Dans une application orientée
objet, le modèle métier d'une application objet capture la connaissance
sémantique du domaine du problème. Les développeurs doivent manipuler et
interagir avec des objets sans devoir trop s'inquiéter à propos du
stockage de données et des détails d'extraction.
Un sous-ensemble bien défini d'interfaces persistantes (enregistrer,
supprimer, trouver) doit être fourni aux développeurs d'applications.
Des patterns courants émergent d'applications relationnelles objet.
Les professionnels informatiques qui ont à plusieurs reprises croisés cette
lacune commencent à comprendre et à reconnaître certaines structures et
certains comportements montrant des applications relationnelles objet réussies.
Ces structures et ces comportements ont été formalisés par les spécifications
de haut niveau des services CORBA (qui s'appliquent tout aussi bien à des
systèmes COM/DCOM).
Les spécifications des services CORBA qui sont applicables et utiles à prendre
en considération pour le mappage relationnel objet sont les suivantes :
Les sections suivantes utilisent ces catégories pour structurer une
discussion sur les services relationnels objet courants. Pour plus de détails,
le lecteur est invité à se rapporter aux spécifications CORBA appropriées.
La persistance est un terme utilisé pour décrire comment les objets
utilisent un support de stockage secondaire pour gérer leur état à travers des
sessions discrètes. La persistance permet à un utilisateur d'enregistrer des
objets dans une session et d'y accéder lors d'une session ultérieure.
Lorsqu'ils sont accédés ultérieurement, leur état (par exemple, attributs) sera
le même que celui de la session précédente. Dans des systèmes
multi-utilisateurs, il peut ne pas en être de même car d'autres utilisateurs
peuvent accéder aux mêmes objets et les modifier.
La persistance est associée à d'autres services abordés dans cette section. La
considération des relations, de la simultanéité et autres est intentionnelle
(et cohérente avec la décomposition des services par CORBA).
Exemples de services spécifiques fournis par la persistance :
- Gestion des connexions de source de données : les
applications relationnelles objet doivent initialiser une connexion avec la source
de données physiques. Les systèmes de base de données relationnelle
nécessite l'identification du serveur et de la base de données.
La spécificité de la gestion des connexions tend à être spécifique au fournisseur
de base de données et la structure doit être conçue conformément de manière
flexible.
- Extraction d'objet : lorsque des objets sont restaurés
de la base de données, des données sont extraites de la base de données et
traduites en objets. Ce processus implique l'extraction des données de
structures spécifiques à la base de données extraites de la source de données,
la conversion des données de types de base de données en types et/ou
classes d'objet appropriés, la création de l'objet approprié et la définition des
attributs spécifiques à l'objet.
- Stockage d'objets : le processus de stockage d'objets
reflète l'extraction d'objets. Les valeurs des attributs appropriés sont
extraites de l'objet, une structure spécifique à la base de données est créée
avec les valeurs d'attributs (il peut s'agir d'une chaîne SQL, d'une procédure stockée ou d'un appel de procédure éloignée spécial), et la structure est
envoyée à la base de données.
- Suppression d'objets : lorsque des objets sont supprimés
d'un système, les données qui leur sont associées sont supprimées de la base de
données relationnelle. La suppression d'objets nécessite que les
informations appropriées soient extraites de l'objet, qu'une demande d'objet soit
constituée (il peut s'agir d'une chaîne SQL, d'une procédure stockée ou
d'un appel de procédure éloignée) et que celle-ci soit soumise à la base de
données. Notez que dans certains langages, tels que Smalltalk et Java, la
suppression explicite n'est pas prise en charge. En revanche, une stratégie
appelée récupération de place l'est. Les structures
de persistance prenant en charge ces langages doivent fournir une alternative
pour retirer des données de la base de données, une fois que les applications
n'y font plus référence. Un moyen courant consiste pour la base de données à
gérer les nombres de références correspondant au nombre de
fois qu'un objet est référencé par les autres objets. Lorsque le nombre de
référence d'un objet tombe à zéro, aucun objet n'y fait plus référence et il
est alors possible de le supprimer. Il peut être
acceptable de supprimer des objets dont le nombre de références est à
zéro, puisque même si un objet n'est plus référencé, il peut toujours être
demandé. Une règle s'appliquant à toute la base de données lorsque la
suppression d'objets est autorisée, demeure nécessaire.
Le stockage d'objets persistants est peu utile sans mécanisme de
recherche et d'extraction des objets spécifiques. Les fonctions de requête
permettent aux applications d'interroger et d'extraire des objets en fonction
de critères variés. Les opérations de requête de base fournies par une
structure de mappages relationnelle objet sont "find" et "find unique". L'opération
"find unique" extrait un objet spécifique et l'opération "find" renvoie une
collection d'objets basée sur un critère de recherche.
Les fonctions de requête de magasin de données varient de façon importante.
Des magasins de données basés sur de simples fichiers peuvent implémenter des
opérations de requête rigides, développées en interne, tandis que des
systèmes relationnels fournissent un langage LMD flexible. Les
structures de mappages relationnels objet étendent le modèle de
requête relationnel pour en faire un modèle centré objet plutôt
que centré données. Des mécanismes de passe-système sont également
implémentés pour utiliser la flexibilité des requêtes relationnelles et les
extensions spécifiques aux fournisseurs (par exemple, des procédures
mémorisées).
Notez qu'il existe un conflit potentiel entre les mécanismes de requête
basés sur une base de données et le paradigme objet : les mécanismes de
requête de base de données sont guidés par des valeurs
d'attributs (colonnes) d'une table. Dans les objets correspondants, le
principe d'encapsulation nous empêche de voir les valeurs des attributs. Ils
sont encapsulés par les opérations de la classe.
L'encapsulation simplifie la modification des applications. Grâce à elle, nous
pouvons modifier la structure interne d'une classe sans s'occuper des classes
dépendantes, tant que les opérations de la classe visibles publiquement ne
sont pas modifiées. Un mécanisme de requête basé sur la base de données dépend
de la représentation interne d'une classe, brisant
effectivement l'encapsulation. Le défi pour la structure consiste à empêcher
les requêtes de rendre les applications fragiles face aux modifications.
La prise en charge transactionnelle permet au développeur d'applications de
définir une unité de travail atomisée. Dans la terminologie de base de données,
cela signifie que le système doit pouvoir appliquer un ensemble de modifications
sur la base de données ou s'assurer qu'aucune des modifications n'est appliquée.
Les opérations au sein d'une transaction s'exécutent toutes avec succès ou
la transaction échoue en totalité. Les structures
relationnelles objet doivent au minimum fournir une fonction de
transaction engagement/annulation de type base de données relationnelle.
La conception des structures relationnelles objet dans un environnement
multi-utilisateur peut présenter de nombreux défis et un intérêt particulier
doit y être apporté.
Outre les fonctions fournies par la structure de persistance, l'application
doit comprendre comment traiter les erreurs. Lorsqu'une transaction échoue
ou est annulée, le système doit être en mesure de restaurer son état à un
état antérieur fiable, généralement grâce en lisant les informations de l'état
antérieur dans la base de données. Ainsi, il existe une étroite interaction
entre la structure de persistance et la structure de traitement des erreurs.
Des systèmes orientés objet multi-utilisateurs doivent contrôler les accès
simultanés aux objets. Lorsqu'un objet est accédé simultanément par
plusieurs utilisateurs, le système doit fournir un mécanisme pour s'assurer que
les modifications apportées à l'objet dans le magasin persistant se
produisent de manière prévisible et contrôlée.
Les structures relationnelles objet peuvent implémenter des contrôles
de simultanéité pessimistes et/ou optimistes.
- Le contrôle de simultanéité pessimiste nécessite
que les développeurs d'applications spécifient leurs intentions lorsque l'objet
est extrait du magasin de données (par exemple, lecture seule, verrou en
écriture, ...). Si des objets sont verrouillés, d'autres utilisateurs peuvent
être bloqués lors de l'accès à l'objet et attendre que le verrou soit libéré.
La simultanéité pessimiste doit être utilisée et implémentée avec précaution
du fait qu'il est possible de créer des situations d'interblocage.
- Le contrôle de simultanéité optimiste présume qu'il
est peu probable que le même objet soit accédé simultanément.
Les conflits de simultanéité sont détectés lorsque les modifications
sont enregistrées dans la base de données. Généralement, si l'objet a
été modifié par un autre utilisateur depuis son extraction, une erreur
est renvoyée à l'application, indiquant un incident lors de la
modification. Il est de la responsabilité de l'application de détecter et de
traiter l'erreur. La structure doit donc mettre en cache les valeurs
simultanées des objets et les comparer par rapport à la base de données.
La simultanéité optimiste est moins coûteuse s'il y a peu de conflits de
simultanéité, mais plus onéreuse si le nombre de conflits est relativement
important (du fait du besoin de recommencer le travail si des conflits se
produisent).
Toutes les applications faisant usage de données partagées doivent
utiliser la même stratégie de simultanéité. Il n'est pas possible de mélanger
un contrôle de simultanéité optimiste et pessimiste dans les mêmes données
partagées, sinon une altération risque de se produire.
Le besoin de stratégie de simultanéité cohérente est mieux géré via une
structure de persistance.
Les objets ont des relations avec d'autres objets. Un objet Commande
comporte de nombreux objets de ligne article. Un objet Livre comporte de
nombreux objets Chapitre. Un objet Employé appartient exactement à un objet
Entreprise. Dans les systèmes relationnels, les relations entre entités sont
implémentées à l'aide de références de clé externe/clé primaire. Dans les
systèmes orientés objet, les relations sont généralement implémentées de
manière explicite via des attributs. Si un objet Commande comporte des lignes
articles, l'objet Commande contient un attribut nommé ligneArticle. Cet
attribut comporte de nombreux objet Ligne article.
Les aspects relationnels d'une structure relationnelle objet sont
interdépendants des services de persistance, de transaction et de requête.
Lorsqu'un objet est stocké, extrait, qu'il subit une transaction ou une
requête, ses objets associés doivent être pris en considération :
- Lorsqu'un objet est extrait, ses objets associés doivent-ils être
extraits également ? Tout simplement, oui. Mais si les objets
associés ne sont pas nécessaire, l'opération est très onéreuse. Une bonne
structure permet un mélange de stratégies.
- Lorsqu'un objet est stocké, ses objets associés doivent-ils être
également stockés s'ils ont été modifiés ? Là encore, la réponse dépend
du contexte.
Bien que par conception, il soit plus avantageux de prendre
en compte des services relationnels objet séparément, leurs implémentations de
structure relationnelle objet sont co-dépendantes.
Les services doivent être implémentés de façon cohérente non seulement sur
les organisations individuelles, mais sur toutes les applications qui
partagent les mêmes données. Une structure est le moyen le plus économique pour
y parvenir.
| |
|