UML : des classes à la base de données
Le diagramme de classes se traduit en tables selon des règles proches de celles de Merise (Du MCD au modèle logique). Le schéma obtenu est le même ; seuls changent le vocabulaire et la place des multiplicités.
Règle 1 : une classe devient une table
Section intitulée « Règle 1 : une classe devient une table »Chaque attribut devient une colonne ; on ajoute une clé primaire.
Client (numClient, nom, email, adresse) → table client (num_client PK, nom, email, adresse)| UML | SQL |
|---|---|
| Classe | Table |
| Attribut | Colonne |
Attribut {id} |
Clé primaire |
Attribut [0..1] (facultatif) |
Colonne nullable |
| Attribut obligatoire | NOT NULL |
Attribut {unique} |
UNIQUE |
Attribut multi-valué (telephones [0..*]) |
Table liée (1FN) |
Attribut dérivé (/age) |
Aucune colonne (calculé) |
| Opération (méthode) | Aucune colonne (reste dans le code) |
Les noms se traduisent : numClient (UML, camelCase) → num_client (SQL, snake_case).
Règle 2 : association 1 — 0..* (un à plusieurs)
Section intitulée « Règle 2 : association 1 — 0..* (un à plusieurs) »La clé étrangère va du côté « plusieurs » (la classe de multiplicité 0..* ou 1..*).
Client 1 ──── 0..* Commande → commande.num_client REFERENCES client| Multiplicité du côté « un » | Clé étrangère |
|---|---|
1 |
NOT NULL |
0..1 |
Nullable |
Mémo : la clé étrangère est dans la table du côté où l’on trouve 0..* ou 1..*.
Règle 3 : association 0..* — 0..* (plusieurs à plusieurs)
Section intitulée « Règle 3 : association 0..* — 0..* (plusieurs à plusieurs) »Une table d’association avec les deux clés étrangères (clé primaire composée) ; les attributs de la classe d’association deviennent des colonnes.
Commande 1..* ──── 0..* Article avec classe d'association LigneCommande (quantite, prixUnitaire)→ ligne_commande (num_commande FK, reference FK, quantite, prix_unitaire, PK (num_commande, reference))Règle 4 : association 1 — 1 ou 1 — 0..1
Section intitulée « Règle 4 : association 1 — 1 ou 1 — 0..1 »Clé étrangère avec UNIQUE dans la table qui dépend de l’autre (la plus « faible »).
Client 1 ──── 0..1 Compte → compte.num_client UNIQUE NOT NULL REFERENCES clientRègle 5 : composition
Section intitulée « Règle 5 : composition »La partie n’existe pas sans le tout : clé étrangère NOT NULL avec ON DELETE CASCADE ; la partie peut être identifiée par rapport au tout (clé composée) ou avoir son propre identifiant.
Commande ◆──── 1..* LigneCommande → ligne_commande.num_commande NOT NULL REFERENCES commande ON DELETE CASCADEPour une agrégation ou une association simple : ON DELETE RESTRICT (ou SET NULL si la clé est facultative).
Règle 6 : association réflexive
Section intitulée « Règle 6 : association réflexive »Employe 0..1 ── dirige ── 0..* Employe → employe.num_manager REFERENCES employe (nullable)Pour une réflexive 0..* — 0..* (amis, parrainages) : table d’association avec deux clés vers la même table.
Règle 7 : héritage
Section intitulée « Règle 7 : héritage »Trois stratégies, comme pour la généralisation de Merise :
| Stratégie | Description | Convient si |
|---|---|---|
Table unique (SINGLE_TABLE) |
Une table avec toutes les colonnes + colonne type |
Sous-classes très proches, requêtes polymorphes fréquentes |
Une table par classe concrète (TABLE_PER_CLASS) |
Chaque classe fille a sa table avec toutes ses colonnes (héritées comprises) | Peu de requêtes sur « tous les types » |
Table parente + tables filles (JOINED) |
personne (commun) + client, employe avec clé primaire = clé étrangère vers personne |
Modèle normalisé, sous-classes différentes |
Les ORM (Hibernate, TypeORM, Prisma, Doctrine) proposent ces stratégies sous des noms voisins. Voir Du MCD au modèle logique pour les avantages et inconvénients.
Règle 8 : énumérations
Section intitulée « Règle 8 : énumérations »«enumeration» Statut { nouvelle, payee, expediee, annulee }| Traduction | Exemple |
|---|---|
Colonne + CHECK |
statut varchar(20) CHECK (statut IN ('nouvelle', 'payee', 'expediee', 'annulee')) |
Type ENUM du SGBD |
PostgreSQL : CREATE TYPE statut AS ENUM (...) ; MariaDB : ENUM(...) |
| Table de référence | statut (code PK, libelle) + clé étrangère : évolutif, recommandé si la liste change |
Règle 9 : types
Section intitulée « Règle 9 : types »| UML / TypeScript | PostgreSQL | MariaDB / MySQL |
|---|---|---|
int |
integer |
INT |
long |
bigint |
BIGINT |
String |
varchar(n) / text |
VARCHAR(n) / TEXT |
Money (montant) |
numeric(10,2) |
DECIMAL(10,2) |
boolean |
boolean |
BOOLEAN |
DateTime |
timestamptz |
DATETIME |
Date |
date |
DATE |
UUID |
uuid |
UUID (MariaDB 10.7+) / CHAR(36) |
Pour des montants, éviter float : numeric/DECIMAL ou entier en centimes.
Le script de la boutique, produit par les règles
Section intitulée « Le script de la boutique, produit par les règles »CREATE TABLE client ( num_client bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, nom varchar(100) NOT NULL, email varchar(255) NOT NULL UNIQUE, adresse text);
CREATE TABLE article ( reference varchar(20) PRIMARY KEY, libelle varchar(200) NOT NULL, prix numeric(10,2) NOT NULL CHECK (prix >= 0), stock integer NOT NULL DEFAULT 0 CHECK (stock >= 0));
CREATE TABLE commande ( num_commande bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, date_commande timestamptz NOT NULL DEFAULT now(), statut varchar(20) NOT NULL DEFAULT 'nouvelle' CHECK (statut IN ('nouvelle', 'payee', 'expediee', 'annulee')), num_client bigint NOT NULL REFERENCES client (num_client) ON DELETE RESTRICT);
CREATE TABLE ligne_commande ( num_commande bigint NOT NULL REFERENCES commande (num_commande) ON DELETE CASCADE, reference varchar(20) NOT NULL REFERENCES article (reference) ON DELETE RESTRICT, quantite integer NOT NULL CHECK (quantite >= 1), prix_unitaire numeric(10,2) NOT NULL CHECK (prix_unitaire >= 0), PRIMARY KEY (num_commande, reference));C’est le script détaillé dans Du modèle physique au SQL (y compris les index, les variantes MariaDB et SQLite et les migrations).
Correspondance avec un ORM
Section intitulée « Correspondance avec un ORM »Les mêmes classes se déclarent dans un ORM, qui génère ou vérifie le schéma :
// exemple de schéma Prisma (autre outil possible : TypeORM, Drizzle)// model Client { numClient Int @id @default(autoincrement()) nom String email String @unique commandes Commande[] }// model Commande { numCommande Int @id @default(autoincrement()) client Client @relation(fields: [numClient], references: [numClient]) numClient Int lignes LigneCommande[] }Quel que soit l’ORM, relire le SQL produit : l’ORM traduit le modèle, il ne le conçoit pas à votre place. Pour MongoDB, Mongoose décrit des schémas de documents, avec des choix différents (imbrication ou références : Mongoose : relations et agrégation).
Cohérence entre classes, base et API
Section intitulée « Cohérence entre classes, base et API »| Niveau | Contenu | Validation |
|---|---|---|
| Base de données | Tables, contraintes | NOT NULL, UNIQUE, CHECK, clés étrangères |
| Code (classes ou types) | Types TypeScript | Compilation (TypeScript : types de base) |
| Entrées d’API | Schémas | Zod (TypeScript : projets Node.js et web) |
Les trois doivent exprimer les mêmes règles : la base reste la dernière ligne de défense, quel que soit le code qui y écrit.
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
| Clé étrangère du mauvais côté | Elle va du côté 0..* / 1..* |
| Table associative oubliée | Association *—* : table d’association (ou classe d’association) |
Colonnes NULL en grand nombre |
Héritage en table unique mal adapté : séparer |
| Schéma généré par l’ORM illisible ou inefficace | Lire le SQL produit, ajouter les index, ajuster le mapping |
| Suppression en cascade inattendue | Seule la composition justifie CASCADE |
| Le code et la base divergent | Migrations versionnées, schéma de référence unique |
| Montants qui s’arrondissent mal | numeric/DECIMAL ou centimes entiers |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune propre à Ubuntu : le script s’exécute sur le SGBD installé (PostgreSQL, MariaDB).