Bonsoir passant13,
Pour être plus à l’aise, je bascule vers Looping (gratuit) qui permet de représenter des MCD aussi bien que des diagrammes de classes.
Le diagramme de classes ci-dessous :
est issu du MCD :
Je rappelle que les cardinalités (multiplicités) du MCD sont inversées par rapport à celles du diagramme de classes.
La cardinalité 1,1(R) portée par la patte connectant COMMUNE et COM_DEP se lit : la commune C est identifiée relativement au département D, ce qui veut dire qu’au stade SQL, la clé primaire de la table COMMUNE sera la paire {departementId, communeId}. En plus, l’identification relative a donné lieu à une composition UML.

Envoyé par
passant13
J'ai rajouté les id sauf pour la table Commune ou le contexte permet d'utiliser la chaîne Commune comme clé primaire. (une particularité du système considéré)
Utiliser des propriétés naturelles (par exemple Commune) pour les clés primaires a causé des ravages dans le passé et ça n’est pas fini. L’attribut CommuneId du MCD (ou idCommune, peu importe le mode de nommage) est artificiel, et donnera lieu en SQL à la clé primaire de la table COMMUNE, tandis que le code de la commune (communeCodeInsee ci-dessus) fera l’objet d’une clé alternative (contrainte "UNIQUE" en SQL). L’attribut communeId étant artificiel, il s’en suit qu’il ne doit avoir aucune valeur sémantique, il est donc invariant et garantit la validité des liens entre les tables SQL (clés étrangères référençant les clés primaires). Les valeurs des identifiants artificiels n’ont pas à être utilisées par les applications, lesquelles, pour accéder aux données useront des clés alternatives telles que {departementNumero}, {communeCodeInsee}, {lieuCode}, etc.

Envoyé par
passant13
Le cœur du problème c'est qu'on peut avoir deux lieux identiques (dont le nom est identique) situés dans deux communes différentes.
Dans les diagrammes ci-dessus, un lieu détermine une commune, ce qui n’interdit aucunement que le même nom de lieu existe pour deux communes différentes. Exemple :
COMMUNE {departementId communeId communeCodeInsee ...}
5 1 30189 ...
5 4 30028 ...
LIEU {departementId communeId lieuId lieuCode lieuNom ...}
5 1 1 C0041 Canet ...
5 4 1 C0178 Canet ...
Les attributs soulignés sont les éléments de la clé primaire des tables.

Envoyé par
passant13
J'en suis arrivé provisoirement à ce schéma et ca ne va toujours pas !
Il faut faire disparaître l’attribut #Commune de la classe Lieu, il sera accessible en SQL par une requête de jointure entre les tables COMMUNE et lieu. Exemple :
SELECT communeCodeInsee
FROM LIEU AS x JOIN COMMUNE AS y ON x.departementId = y.departementId
AND x.communeId = y.communeId
WHERE lieuCode = 'C0041'
;
Vous observerez qu’on ne se sert absolument pas des valeurs des attributs artificiels departementId, communeId, on n’utilise que les valeurs des attributs naturels (lieuCode dans cet exemple).
En passant, à partir de cette de cette requête vous pouvez concevoir une vue SQL (qui n’est jamais qu’une table virtuelle) :
CREATE VIEW LIEU_COMMUNE (communeCodeInsee, lieuCode, lieuNom)
AS
SELECT communeCodeInsee, lieuCode, lieuNom
FROM LIEU AS x JOIN COMMUNE AS y ON x.departementId = y.departementId
AND x.communeId = y.communeId
;
On obtient le résultat en accédant à la vue :
SELECT communeCodeInsee
FROM LIEU_COMMUNE
WHERE lieuCode = 'C0041'
;
L’emploi des vues plutôt que des tables devrait vous faciliter la vie pour les formulaires et compagnie.
On reviendra plus tard sur l’histoire des sites Web.
Annexe :
Code SQL généré par Looping, hors Web (notez la présence de "UNIQUE")
CREATE TABLE DEPARTEMENT(
departementId INTEGER,
departementNumero VARCHAR(3) NOT NULL UNIQUE,
departementNom VARCHAR(32) NOT NULL UNIQUE,
PRIMARY KEY(departementId)
);
CREATE TABLE COMMUNE(
departementId INTEGER,
communeId INTEGER,
communeCodeInsee VARCHAR(6) NOT NULL UNIQUE,
communeNom VARCHAR(48) NOT NULL,
PRIMARY KEY(departementId, communeId),
FOREIGN KEY(departementId) REFERENCES DEPARTEMENT(departementId)
);
CREATE TABLE LIEU(
departementId INTEGER,
communeId INTEGER,
lieuId INTEGER,
lieuCode VARCHAR(8) NOT NULL UNIQUE,
lieuNom VARCHAR(48) NOT NULL,
PRIMARY KEY(departementId, communeId, lieuId),
FOREIGN KEY(departementId, communeId) REFERENCES COMMUNE(departementId, communeId)
);
CREATE TABLE HOTEL(
hotelId INTEGER,
hotelCode VARCHAR(8) NOT NULL UNIQUE,
hotelNom VARCHAR(48) NOT NULL,
departementId INTEGER NOT NULL,
communeId INTEGER NOT NULL,
lieuId INTEGER NOT NULL,
PRIMARY KEY(hotelId),
FOREIGN KEY(departementId, communeId, lieuId) REFERENCES LIEU(departementId, communeId, lieuId)
);
Partager