B03 - Traduire un héritage UML en tables : TPH, TPT, TPC
Objectif
Une base relationnelle ne connaît pas l’héritage (« un Meuble est un Produit »). Savoir choisir et coder les 3 stratégies. Corrigé détaillé du cours : Exercice Héritage - Produits et Véhicules.
1. Le cas d’étude
classDiagram class Produit { <<abstract>> +String reference +String designation +Decimal prixVente +int stock } class Meuble { +int hauteur +int largeur +int profondeur } class Kit { +String urlNotice } class Equipement { +String categorie } Produit <|-- Meuble Produit <|-- Kit Produit <|-- Equipement
2. Les trois stratégies
flowchart LR subgraph TPH["TPH : 1 table"] T1["PRODUITS<br/>reference PK<br/>designation, prix, stock<br/>type_produit (discriminant)<br/>hauteur NULL, url_notice NULL,<br/>categorie NULL…"] end subgraph TPT["TPT : 1 table mère + 1 par fille"] M["PRODUITS (commun)"] --- F1["MEUBLES<br/>reference PK+FK"] M --- F2["KITS<br/>reference PK+FK"] M --- F3["EQUIPEMENTS<br/>reference PK+FK"] end subgraph TPC["TPC : 1 table par classe concrète"] C1["MEUBLES<br/>(tous les champs)"] C2["KITS<br/>(tous les champs)"] C3["EQUIPEMENTS<br/>(tous les champs)"] end
TPH - Table Per Hierarchy (choix de l’exercice)
CREATE TABLE Produits (
reference VARCHAR(50) PRIMARY KEY,
designation NVARCHAR(200) NOT NULL,
prix_vente DECIMAL(10,2) NOT NULL CHECK (prix_vente >= 0),
stock INT NOT NULL DEFAULT 0,
type_produit VARCHAR(20) NOT NULL
CONSTRAINT CK_Produit_Type CHECK (type_produit IN ('MEUBLE', 'KIT', 'EQUIPEMENT')),
id_finition INT NULL REFERENCES Finitions(id_finition),
hauteur_cm INT NULL,
url_notice NVARCHAR(500) NULL,
-- Règle métier : finition obligatoire pour meubles et kits, interdite pour les équipements
CONSTRAINT CK_Finition CHECK (
(type_produit = 'EQUIPEMENT' AND id_finition IS NULL) OR
(type_produit <> 'EQUIPEMENT' AND id_finition IS NOT NULL))
);
SELECT * FROM Produits WHERE type_produit = 'KIT'; -- aucune jointureTPT - Table Per Type
CREATE TABLE Produits (
reference VARCHAR(50) PRIMARY KEY,
designation NVARCHAR(200) NOT NULL,
prix_vente DECIMAL(10,2) NOT NULL,
stock INT NOT NULL DEFAULT 0
);
CREATE TABLE Meubles (
reference VARCHAR(50) PRIMARY KEY REFERENCES Produits(reference), -- PK = FK
id_finition INT NOT NULL REFERENCES Finitions(id_finition),
hauteur_cm INT NOT NULL
);
CREATE TABLE Kits (
reference VARCHAR(50) PRIMARY KEY REFERENCES Produits(reference),
id_finition INT NOT NULL REFERENCES Finitions(id_finition),
url_notice NVARCHAR(500) NOT NULL
);
-- La composition ne peut lier QUE des kits à des meubles : garanti par les FK
CREATE TABLE Kit_Meuble (
ref_kit VARCHAR(50) REFERENCES Kits(reference),
ref_meuble VARCHAR(50) REFERENCES Meubles(reference),
quantite INT NOT NULL CHECK (quantite > 0),
PRIMARY KEY (ref_kit, ref_meuble)
);
-- Insérer un meuble = 2 INSERT dans une transaction
BEGIN TRANSACTION;
INSERT INTO Produits VALUES ('MEU-001', N'Banquette', 349.00, 5);
INSERT INTO Meubles VALUES ('MEU-001', 1, 45);
COMMIT;TPC - Table Per Concrete class
Pas de table mère : chaque table répète les colonnes communes. Simple, mais une ligne de commande ne peut plus pointer vers « un produit quelconque » avec une seule clé étrangère → rarement adapté.
3. Comparatif
| Critère | TPH | TPT | TPC |
|---|---|---|---|
| Nombre de tables | 1 | 1 + n | n |
| Colonne discriminante | Oui | Non | Non |
| Colonnes NULL | Beaucoup | Aucune artificielle | Aucune |
NOT NULL sur les attributs spécifiques | Via CHECK conditionnels | Natif | Natif |
| Lecture | ⚡ Rapide (0 jointure) | Jointures | Rapide par type, UNION pour tout lister |
| Écriture | 1 INSERT | 2 INSERT (transaction) | 1 INSERT |
| FK vers « un produit quelconque » | ✅ | ✅ | ❌ |
| FK vers « un meuble uniquement » | ❌ (trigger) | ✅ | ✅ |
| Quand l’utiliser | Peu d’attributs spécifiques, lecture intensive (e-commerce) | Beaucoup d’attributs spécifiques obligatoires, intégrité stricte | Sous-types totalement indépendants |