Aller au contenu

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.

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

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 client

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 CASCADE

Pour une agrégation ou une association simple : ON DELETE RESTRICT (ou SET NULL si la clé est facultative).

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.

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.

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

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

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

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.

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