Instructions: Génération de code de base de données relationnelles
Les instructions suivantes décrivent les étapes impliquées dans la génération de code d'une base de données et dans le mappage des tables de modèle de données obtenues aux classes de conception du modèle de conception.
Relations
Eléments connexes
Description principale

Introduction

Les instructions suivantes décrivent les étapes impliquées dans la génération de code d'une base de données et dans le mappage des tables de modèle de données obtenues aux classes de conception du modèle de conception. Ce processus peut être utilisé par le concepteur de base de données afin d'inoculer le développement des modifications apportées à la base de données dans le cadre d'un cycle de développement d'évolution. Le concepteur de base de données devra gérer le processus de génération de code tout au long du cycle de développement du projet. Dans de nombreux cas, le processus de génération de code est effectué dans les premières phases du cycle de développement du projet et les changements apportés à la conception des données sont gérés de manière incrémentielle sans qu'il soit nécessaire de procéder à d'autres générations de code de la base de données.

Les grandes étapes du processus de génération de code d'une base de données et de transformation des éléments de modèle de données obtenus en éléments de modèle de conception sont les suivantes :

  • Créez un modèle physique de données contenant des tables afin de représenter l'agencement physique des données persistantes dans la base de données. Cette étape peut être réalisée automatiquement à l'aide des outils fournis avec le système de gestion de base de données relationnelle (SGBDR) ou en recourant à la plupart des outils modernes de modélisation visuelle.
  • Transformez les tables du modèle physique de données en classes de conception dans le modèle de conception. Cette étape peut être réalisée à l'aide d'une combinaison d'outils automatisés utilisés pour la transformation initiale, suivie de réglages manuels.
  • Définissez des associations entre les classes du modèle de conception.
  • Définissez les opérations appropriées sur les classes du modèle de conception à partir des actions effectuées sur les éléments de modèle de données correspondants.
  • Regroupez les classes du modèle de conception en sous-systèmes et packages, selon les besoins.

Génération de code d'une base de données SGBDR ou d'un script de langage de définition de données pour générer un modèle de données

Le processus de génération de code d'une base de données ou d'un script de langage de définition de données produit généralement un ensemble d'éléments de modèle (tables, vues, procédures stockées, etc.). Selon la complexité de la base de données, le concepteur de base de données peut être contraint de partitionner les éléments de modèle soumis à la génération de code en packages de domaine qui contiennent des ensembles de tables logiquement liés.

Transformation du modèle de données en modèle de conception

La procédure suivante peut être observée pour produire des classes de conception à partir d'éléments de modèle du modèle de données. Répliquer la structure de la base de données dans un modèle de classe est relativement simple. Le processus détaillé ci-dessous décrit l'algorithme de transformation des éléments de modèle de données en éléments de modèle de conception.

Le tableau ci-dessous contient un résumé du mappage général entre les éléments de modèle de conception et les éléments de modèle de données.

Elément de modèle de données 

Elément de modèle de conception correspondant 

Table  Classe 
Colonne  Attribut 

Relation non identifiante 

Association 

Table d'intersection

 

Classe d'association

Association plusieurs à plusieurs

Association qualifiée 

Relation identifiante 

Agrégation 

Cardinalité 

 

Multiplicité 

 
Contrainte de vérification de table avec une clause d'énumération  Classe <<ENUM>> 
Schéma  Package 

Certains éléments de modèle du modèle de données n'ont aucune corrélation directe dans le modèle de conception. Ces éléments comprennent les espaces de table et la base de données elle-même, qui modèlent les caractéristiques de stockage physique de la base de données et sont représentés comme des composants. On trouve également les vues de la base de données, qui constituent des tables « virtuelles » et n'ont aucun sens dans le modèle de conception.  Pour finir, les index des clés primaires des tables et les fonctions de déclenchement de la base de données, qui sont utilisés pour optimiser le fonctionnement de la base de données, n'ont de sens que dans le contexte de la base de données et du modèle de données.

Transformer une table en classe

Pour chaque table que vous souhaitez transformer, créez une classe pour représenter cette table. Pour chaque colonne, créez un attribut sur la classe avec le type de données qui convient. Essayez de faire correspondre du mieux possible le type de données de l'attribut et celui de la colonne associée.

Exemple

Etudiez la table de base de données Client, avec la structure suivante, représentée dans la figure ci-dessous :

Nom de colonne Type de données
ID_client Numéro
Nom Varchar
Rue Varchar
Ville Varchar
Etat/Province Char(2)
Code postal Varchar
Pays Varchar

Définition de table pour la table Client

A partir de ce point, nous créons une classe, Client, dotée de la structure indiquée dans la figure suivante :

Définition de la classe Client

Classe Client initiale

Dans cette classe Client initiale, on compte un attribut pour chaque colonne de la table Client. Chaque attribut se caractérise par une visibilité publique, car n'importe laquelle des colonnes de la table d'origine peut faire l'objet d'une requête.

Nous attirons votre attention sur l'icône « + » affichée à gauche de l'attribut, et qui indique que ce dernier est « public » ; par défaut, tous les attributs dérivés des tables SGBDR doivent être publics, car les SGBDR autorisent généralement que n'importe quelle colonne fasse l'objet de requêtes sans aucune restriction.

Identifier les classes imbriquées ou implicites

La classe qui découle du mappage direct table-classe contient souvent des attributs pouvant être séparés en une classe distincte, particulièrement dans les cas où ces attributs apparaissent dans un certain nombre de classes traduites. Ces « attributs redondants » peuvent découler d'une dénormalisation des tables (opérée pour des raisons de performances) ou peuvent être la conséquence d'un modèle de données trop simplifié. Dans ces cas de figure, divisez la classe correspondante en deux classes ou plus afin de représenter une vue normalisée des tables.

Exemple

Après avoir défini la classe Client ci-dessus, nous pouvons définir une classe Adresse qui contient toutes les informations liées à l'adresse (en présumant que notre système comportera d'autres parties dotées d'adresses), ce qui nous donne les classes suivantes :

Diagramme décrit dans le texte d'accompagnement.

Classe Client revue, avec la classe Adresse extraite

L'association établie entre ces deux classes est une agrégation, car l'adresse du client peut être envisagée comme faisant partie du client.

Gestion des relations de clé externe

Pour chaque relation de clé externe de la table, créez une association entre les classes associées, en supprimant l'attribut de la classe qui mappait à la colonne de clé externe. Si cette colonne était initialement représentée comme un attribut, supprimez-le de la classe.

Exemple

Prenons la structure de la table Commande (order) détaillée ci-dessous :

Nom de colonne  Type de données 
Numéro  Numéro 
ID_client  Varchar 

Structure de la table Commande

Dans la table Commande ci-dessus, la colonne ID_client est une référence de clé externe ; cette colonne contient la valeur de clé primaire du Client associé à la Commande. Nous représenterions cela dans le modèle de conception comme suit :

Diagramme UML décrit ci-dessous.

Représentation des relations de clé externe dans le modèle de conception

La clé externe est représentée comme une association entre les classes Commande et Article.

Gestion des relations plusieurs à plusieurs

Les modèles de données SGBDR représentent des relations plusieurs à plusieurs avec ce qu'on appelle une table de jointure ou table d'association. Ces tables permettent aux relations plusieurs à plusieurs d'être représentées à l'aide d'une table intermédiaire qui contient les clés primaires de deux tables différentes pouvant être associées. La raison pour laquelle les tables de jointure sont nécessaires réside dans le fait qu'une référence de clé externe ne peut contenir de référence qu'à une seule valeur de clé externe ; lorsqu'une ligne unique est susceptible d'être liée à de nombreuses autres lignes d'une autre table, une table de jointure est nécessaire afin de les associer.

Exemple

Prenons le cas de Produits, qui peuvent être fournis par n'importe quel fournisseur d'un groupe de Fournisseurs, sachant que n'importe quel Fournisseur peut fournir autant de Produits qu'il le souhaite. Les tables Produit et Fournisseur ont la structure définie ci-dessous :

Table de produits
Nom de colonne Type de données
ID_produit Numéro
Nom Varchar
Description Varchar
Prix Numéro
Table de fournisseur
Nom de colonne Type de données
ID_fournisseur Numéro
Nom Varchar
Rue Varchar
Ville Varchar
Etat/Province Char(2)
Code postal Varchar
Pays Varchar

Définitions de tables Produit et Fournisseur

Pour relier ces deux tables entre elles afin de déterminer quels sont les produits proposés par un fournisseur donné, nous avons besoin d'une table Produit-Fournisseur, qui est définie dans la table ci-dessous.

Table Produit-Fournisseur
Nom de colonne  Type de données 
ID_produit  Numéro 
ID_fournisseur  Numéro 

Définition de la table Produit-Fournisseur

Cette table de jointure contient les clés primaires des produits et des fournisseurs, en les reliant. La présence d'une ligne dans la table indiquerait qu'un fournisseur donné propose un produit donné. Toutes les lignes dont la colonne ID_fournisseur correspond à un identifiant de fournisseur donné afficheraient la liste de tous les produits proposés par ce fournisseur.

Dans le modèle de conception, cette table intermédiaire est redondante, car un objet de modèle peut représenter directement les associations plusieurs à plusieurs. Les classes Fournisseur et Produit et leurs relations sont représentées dans la figure ci-dessous, ainsi que la classe Adresse, qui est extraite de Fournisseur, comme nous l'avons vu.

Diagramme UML décrit dans le libellé.

Représentation des classes Produit et Fournisseur

Mettre en place la généralisation

Vous rencontrerez souvent des tables dont les structures sont assez similaires. Dans le modèle de données, il n'existe pas de concept de généralisation et il n'y a donc aucun moyen de représenter le fait que deux tables ou plus ont une structure en commun. Les structures communes résultent parfois de la dénormalisation opérée pour des questions de performances, comme c'était le cas pour la table « implicite » Adresse évoquée plus haut, que nous avons extraite en une classe distincte. Dans d'autres cas, les tables partagent plus de caractéristiques fondamentales, que nous pouvons extraire dans une classe parente généralisée avec deux sous-classes ou plus. Pour identifier les possibilités de généralisation, recherchez les colonnes redondantes dans plusieurs tables, là où les tables présentent plus de similitudes que de différences.

Exemple

Etudiez les tables suivantes, SoftwareProduct et HardwareProduct, représentées ci-dessous :

Table Software Product
Nom de colonne  Type de données 
ID_produit  Numéro 
Nom  Varchar 
Description  Varchar 
Prix  Numéro 
Version  Numéro 
Table Hardware Product
Nom de colonne  Type de données 
ID_produit  Numéro 
Nom  Varchar 
Description  Varchar 
Prix  Numéro 
Version  Numéro 


Tables SoftwareProduct et HardwareProduct

Remarquez que les colonnes surlignées en bleu sont identiques ; ces deux tables partagent une majeure partie de leur définition et ne diffèrent que légèrement. Nous pouvons représenter ce phénomène en procédant à l'extraction d'une classe Produit commune, avec SoftwareProduct et HardwareProduct comme sous-classes de Produit, comme indiqué dans la figure suivante :

Diagramme décrit dans le texte d'accompagnement.

Classes SoftwareProduct et HardwareProduct, montrant la généralisation à la classe Produit

En regroupant l'ensemble des définitions de classes, la figure ci-dessous montre un diagramme de classes consolidé pour le système Saisie de commande (classes principales uniquement).

Diagramme UML complexe décrit dans le texte d'accompagnement.

Diagramme de classes consolidé pour le système Saisie de commande

Réplication du comportement SGBDR dans le modèle de conception

Répliquer le comportement est plus difficile, car les bases de données relationnelles ne sont généralement pas orientées objet et ne semblent rien avoir de commun avec les opérations réalisées sur une classe du modèle d'objet. Les étapes suivantes peuvent aider à recréer le comportement des classes identifiées ci-dessus :

  1. Créez des opérations afin d'obtenir et de régler chaque attribut. Il doit exister un moyen de régler, de changer et d'effectuer des requêtes sur les valeurs des attributs d'objets. Etant donné que l'unique façon d'accéder aux attributs d'un objet est de le faire via les opérations fournies par la classe, ces opérations doivent être définies sur la classe. Lors de la création des opérations qui définissent la valeur d'un attribut, veillez à bien incorporer toute contrainte de validation susceptible d'être active sur la colonne associée. En l'absence de contraintes de validation, on peut choisir de représenter simplement le fait que les attributs peuvent être obtenus et réglés en les marquant comme ayant une visibilité « publique », comme cela a déjà été fait dans les diagrammes ci-dessus(avec l'icône située à gauche du nom de l'attribut).
  2. Créez une opération sur la classe pour chaque procédure stockée qui fonctionne sur la table associée. Les procédures stockées sont des sous-routines exécutables qui s'exécutent au sein même du SGBD. Cette logique doit être traduite dans le modèle de conception. Si une procédure stockée ne fonctionne que sur une classe, créez une opération sur cette classe avec les mêmes paramètres et le même type de retour que la procédure stockée. Documentez le comportement de la procédure stockée dans l'opération, en veillant à noter dans la description de la méthode que l'opération est implémentée par la procédure stockée.
  3. Créez des opérations afin de gérer les associations entre les classes. Lorsqu'il existe une association entre deux classes, il doit exister une manière de créer, de gérer et de supprimer les associations. Les associations entre objets sont gérées via les références d'objets, ce qui signifie que pour créer une association entre une Commande et un LineItem (c'est-à-dire pour ajouter le LineItem à la Commande), une opération sur Commande doit être appelée, transformant le LineItem en argument (Order.add(aLineItem)). Il doit également exister des façons de supprimer et de mettre à jour l'association (c'est-à-dire Order.remove(aLineItem) et Order.change(aLineItem,aNewLineItem)).
  4. Gestion de la suppression d'objet. Si la langue cible prend en charge la suppression explicite, ajoutez le comportement au destructeur de la classe qui implémente la vérification de l'intégrité référentielle. Dans les cas où il existe des contraintes d'intégrité référentielle dans la base de données, telles que suppression en cascade, le comportement doit être répliqué dans les classes appropriées. Par exemple, la base de données peut définir une contrainte prévoyant que chaque fois qu'une Commande est supprimée, tous les LineItems associés doivent l'être également. Si la langue cible prend en charge la récupération de place, créez un mécanisme permettant de supprimer les lignes des tables lorsque l'objet associé est soumis à une récupération de place. Il est à noter que cette action est plus difficile qu'il n'y paraît (bien qu'elle paraisse déjà difficile), car vous devrez implémenter un mécanisme permettant de garantir qu'aucun client de base de données n'a aucune référence à l'objet devant être soumis à une récupération de place ; il ne suffit pas de se fier aux capacités de récupération de place de l'environnement d'exécution/machine virtuelle car il s'agit uniquement de la vue qu'un client a du monde.
  5. Gestion du comportement sous-entendu par les requêtes. Examinez les instructions SELECT qui accèdent à la table pour voir comment les informations sont récupérées et manipulées. Pour chaque colonne renvoyée directement par une instruction SELECT, réglez la propriété publique de l'attribut associé sur vrai ; tous les autres attributs doivent être réglés sur privé. Pour chaque colonne calculée dans une instruction SELECT, créez une opération sur la classe associée pour calculer et renvoyer la valeur. Lors de la sélection des instructions SELECT, incluez également les instructions SELECT intégrées dans les définitions de vue.

Organisation des éléments dans le modèle de conception

Les classes de conception créées à partir des transformations de table en classes doivent être organisées dans des packages de conception appropriés et/ou sous-systèmes de conception du modèle de conception, selon les besoins, en fonction de la structure architecturale globale de l'application. Pour un aperçu de l'architecture de l'application, consultez Concept : Structures en couches et Concept : Architecture logicielle.