In [1]:
%reload_ext mocodo
Mocodo 4.1.1 loaded.
In [2]:
from IPython import display
from pathlib import Path
import os
if Path.cwd().name != "mocodo_notebook":
    Path("mocodo_notebook").mkdir(parents=True, exist_ok=True)
    os.chdir("mocodo_notebook")

Introduction

Mocodo est un logiciel d'aide à l'enseignement et à l'apprentissage des bases de données relationnelles.

  • En entrée, il prend un MCD (modèle conceptuel de données) décrit dans un langage dédié minimaliste.
  • En sortie, il produit un diagramme entité-association et, à la demande, un MLD (schéma relationnel, sous forme graphique ou textuelle), un DDL (script SQL de création de la base), un diagramme de classes UML, etc.
  • En bonus, il est capable de réarranger automatiquement votre MCD de façon esthétique, et de lui appliquer des opérations de réécriture qui vont du mondain (typographie) à l'académique (décomposition d'associations), en passant par le merveilleux (inférence de types, génération d'exercices et d'exemples).

Vous pouvez utiliser Mocodo :

  • à distance, sans rien installer, avec Mocodo online ;
  • en local, comme n'importe quel programme Python ;
  • dans un document Jupyter Notebook (à l'instar de cette documentation).

Tracé du modèle conceptuel

Ci-dessous, un exemple d'utilisation sous Jupyter Notebook. L'appel du programme est en première ligne ; le texte-source proprement dit, lignes suivantes. En sortie, le diagramme conceptuel, égayé au passage par l'option --colors :

In [3]:
%%mocodo --colors ocean
Client: Réf. client [VARCHAR(8)], Nom [VARCHAR(255)], Prénom [VARCHAR(255)], Adresse [VARCHAR(255)]
Passer, 0N Client, 11 Commande
Commande: Num. commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
Inclure, 1N Commande, 0N Produit: Quantité [INTEGER]
Produit: Réf. produit [VARCHAR(8)], Libellé [VARCHAR(50)], Prix unitaire [DECIMAL(10,2)]
Passer 0,N 1,1 Inclure Quantité 1,N 0,N Client Réf. client Nom Prénom Adresse Commande Num. commande Date Montant Produit Réf. produit Libellé Prix unitaire

Opérations de conversion

L'appel précédent a automatiquement enregistré le texte-source sous le nom de sandbox.mcd. Renommons-le ccp.mcd pour y avoir accès tout au long de ce document.

In [4]:
Path("sandbox.mcd").rename("ccp.mcd");

On peut le récupérer avec --input pour lui appliquer diverses opérations. Ainsi, l'appel suivant génère et affiche son MLD, son diagramme relationnel et son DDL :

In [5]:
%mocodo --input ccp --transform mld diagram ddl --colors mondrian

ccp_mld.md
  • Client (Réf. client, Nom, Prénom, Adresse)
  • Commande (Num. commande, Date, Montant, #Réf. client)
  • Inclure (_#Num. commande_, _#Réf. produit_, Quantité)
  • Produit (Réf. produit, Libellé, Prix unitaire)

ccp_mld.svg


ccp_ddl.sql
CREATE TABLE Client (
  PRIMARY KEY (Ref_client),
  Ref_client VARCHAR(8) NOT NULL,
  Nom        VARCHAR(255),
  Prenom     VARCHAR(255),
  Adresse    VARCHAR(255)
);

CREATE TABLE Commande (
  PRIMARY KEY (Num_commande),
  Num_commande VARCHAR(8) NOT NULL,
  Date         DATE,
  Montant      DECIMAL(10,2),
  Ref_client   VARCHAR(8) NOT NULL
);

CREATE TABLE Inclure (
  PRIMARY KEY (Num_commande, Ref_produit),
  Num_commande VARCHAR(8) NOT NULL,
  Ref_produit  VARCHAR(8) NOT NULL,
  Quantite     INTEGER
);

CREATE TABLE Produit (
  PRIMARY KEY (Ref_produit),
  Ref_produit   VARCHAR(8) NOT NULL,
  Libelle       VARCHAR(50),
  Prix_unitaire DECIMAL(10,2)
);

ALTER TABLE Commande ADD FOREIGN KEY (Ref_client) REFERENCES Client (Ref_client);

ALTER TABLE Inclure ADD FOREIGN KEY (Ref_produit) REFERENCES Produit (Ref_produit);
ALTER TABLE Inclure ADD FOREIGN KEY (Num_commande) REFERENCES Commande (Num_commande);

Dans la suite, pour épargner la frappe, les options --input et --transform seront respectivement abrégées en -i et -t.

Les opérations de conversion ne se limitent pas forcément au schéma relationnel. En voici une qui extrait un dictionnaire des données, par défaut sous la forme d'un tableau Markdown à trois colonnes :

In [6]:
%mocodo -i ccp -t data_dict

ccp_data_dict_3.md
Entité ou association Libellé de l'attribut Type
Client Adresse VARCHAR(255)
" Nom VARCHAR(255)
" Prénom VARCHAR(255)
" Réf. client VARCHAR(8)
Commande Date DATE
" Montant DECIMAL(10,2)
" Num. commande VARCHAR(8)
Inclure Quantité INTEGER
Produit Libellé VARCHAR(50)
" Prix unitaire DECIMAL(10,2)
" Réf. produit VARCHAR(8)

Une autre qui transcrit le MCD dans la notation crow's foot (crow) pour Mermaid (mmd) :

In [7]:
%mocodo -i ccp -t crow:mmd

ccp_erd_crow.mmd
mmd
erDiagram
  Client {
    VARCHAR(8) Ref_client PK
    VARCHAR(255) Nom
    VARCHAR(255) Prenom
    VARCHAR(255) Adresse
  }
  Commande {
    VARCHAR(8) Num_commande PK
    DATE Date
    DECIMAL(10-2) Montant
  }
  Inclure {
    INTEGER Quantite PK
  }
  Produit {
    VARCHAR(8) Ref_produit PK
    VARCHAR(50) Libelle
    DECIMAL(10-2) Prix_unitaire
  }
  Client ||--o{ Commande: Passer
  Inclure }|..|| Commande: DF
  Inclure }o..|| Produit: DF

Le rendu des diagrammes décrits dans des langages-tiers (comme Mermaid) n'est pas directement pris en charge, mais peut être délégué (--defer) de façon transparente au service web approprié. Dans ce cas, c'est la sortie graphique qui est affichée :

In [8]:
%mocodo -i ccp -t crow:mmd --defer

ccp_erd_crow.svg

Opérations de réécriture

Une réécriture transforme un MCD Mocodo en un autre MCD Mocodo (au contraire d'une conversion, qui produit un animal d'une espèce différente).

Heureusement, l'utilisateur n'a pas à réfléchir si la transformation qu'il souhaite appliquer est une réécriture ou une conversion : dans les deux cas, il invoque -t (c'est-à-dire --transform), et Mocodo se débrouille.

En guise de premier exemple de réécriture, mettons les noms des entités et associations (boxes) en majuscules, et les libellés (labels) en ASCII et snake case :

In [9]:
%mocodo -i ccp -t upper:boxes ascii:labels snake:labels --colors brewer+3
PASSER 0,N 1,1 INCLURE Quantite 1,N 0,N CLIENT Ref_client Nom Prenom Adresse COMMANDE Num_commande Date Montant PRODUIT Ref_produit Libelle Prix_unitaire

ccp.mcd
%%mocodo --colors brewer+3
CLIENT: Ref_client [VARCHAR(8)], Nom [VARCHAR(255)], Prenom [VARCHAR(255)], Adresse [VARCHAR(255)]
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: Num_commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantite [INTEGER]
PRODUIT: Ref_produit [VARCHAR(8)], Libelle [VARCHAR(50)], Prix_unitaire [DECIMAL(10,2)]

Remarquez que l'exécution d'une réécriture affiche, au-dessous du diagramme, le code-source résultant. Celui-ci est précédé de la commande magique originale, privée de l'option -i et de toute opération de réécriture. Ces dispositions permettent de continuer à travailler directement dessus si on le copie-colle dans une autre cellule.

Plusieurs opérations de réécriture de nature sémantique sont également offertes. Par exemple, on peut décomposer un MCD quelconque en un MCD équivalent, mais n'employant que des dépendances fonctionnelles et des entités faibles :

In [10]:
%mocodo -i ccp -t explode:weak,arity=2 arrange:wide --seed=3 --colors brewer+3
Passer 0,N 1,1 DF 1,1 1,N DF 1,1 0,N Client Réf. client Nom Prénom Adresse Commande Num. commande Date Montant Inclure Quantité Produit Réf. produit Libellé Prix unitaire

ccp.mcd
%%mocodo --seed=3 --colors brewer+3
Client: Réf. client [VARCHAR(8)], Nom [VARCHAR(255)], Prénom [VARCHAR(255)], Adresse [VARCHAR(255)]
Passer, 0N Client, 11 Commande
Commande: Num. commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
DF, _11 Inclure, 1N Commande
Inclure: _Quantité [INTEGER]
DF, _11 Inclure, 0N Produit
Produit: Réf. produit [VARCHAR(8)], Libellé [VARCHAR(50)], Prix unitaire [DECIMAL(10,2)]

Notez l'argument arrange:wide. Il a procédé à une réorganisation aléatoire des boîtes, ce que l'insertion de deux nouvelles associations de dépendance fonctionnelles avait rendu nécessaire. Quant à l'option --seed=3, elle garantit que le résultat sera le même à chaque exécution.

Après cet aperçu de quelques-unes des fonctionnalités de Mocodo, entrons dans les détails.

Installation et lancement du programme

Comme nous l'avons dit, vous pouvez utiliser Mocodo sans rien installer. Il vous suffit d'aller sur mocodo.net et de commencer à taper votre MCD. Appuyez à tout moment sur le ventilateur pour rafraîchir les diagrammes conceptuel et relationnel. Quand le résultat vous convient, appuyez sur le bouton de téléchargement pour récupérer une archive ZIP contenant tous les fichiers d'entrée et de sortie spécifiés.

Mocodo online est conçu pour une utilisation occasionnelle et/ou interactive, et son interface vise avant tout à la simplicité. Vous n'avez donc accès qu'aux options essentielles du programme. Si vous en voulez davantage, tant en termes de paramétrage que de calcul ou de fonctionnalités, nous vous conseillons d'installer Mocodo sur votre machine.

Installation minimale

Mocodo est un programme écrit en Python 3. Si vous êtes sous macOS ou Linux, il est déjà installé. Dans le cas contraire, vous devrez peut-être le faire.

Une fois Python présent sur votre machine, tapez sous un terminal:

    python -m pip install mocodo

Puis testez-le :

    mocodo

Invoqué sous cette forme, Mocodo récupère le texte d'entrée du MCD dans le répertoire courant sous le nom de sandbox.mcd. Si ce fichier n'existe pas, il y sera automatiquement créé avec un MCD d'exemple. Par la suite, vous n'aurez qu'à le garder ouvert sous un éditeur de texte, afin de le modifier à votre fantaisie avant de relancer la commande.

Si votre système se plaint que cette commande n'existe pas, localisez le fichier mocodo et ajoutez à votre PATH le chemin du répertoire contenant:

Installation complète (recommandé)

  • Installez la distribution Anaconda, qui contient Python 3, Jupyter Notebook et bien plus encore.
  • La ligne donnée précédemment installe en fait, en plus de Mocodo, sa « commande magique » pour Jupyter Notebook. Nous l'avons déjà invoquée plusieurs fois dans ce document :

      python -m pip install mocodo
  • Mocodo fonctionne parfaitement sans autres dépendances que la bibliothèque requests. Cependant, si vous souhaitez générer des figures en PDF ou en PNG :

      python -m pip install cairosvg
  • Si vous souhaitez pouvoir copier directement le résultat d'une réécriture dans le presse-papier :

      python -m pip pyperclip

Pour mettre la « commande magique » mocodo à disposition d'un notebook donné, évaluez dans celui-ci la cellule suivante:

%reload_ext mocodo

Techniquement, %load_ext mocodo suffit, mais cette forme vous épargnera un message d'erreur si vous réévaluez ultérieurement la cellule.

Pour tester la commande :

In [11]:
%%mocodo
MISSION: accomplie
MISSION accomplie

Pour charger automatiquement mocodo à chaque ouverture d'un notebook (ce qui dispense d'évaluer %load_ext mocodo) :

  • exécutez sous un terminal :

          ipython profile create
  • éditez le fichier créé (p. ex.: ~/.ipython/profile_default/ipython_config.py) en remplaçant la ligne suivante :

          # c.TerminalIPythonApp.extensions = []
    
    

    par celle-ci :

          c.InteractiveShellApp.extensions = ["mocodo"]

Syntaxe de description d'un MCD

Notions élémentaires

Entités, associations, attributs, identifiants, cardinalités

In [12]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: Num. commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
PASSER 0,N 1,1 INCLURE Quantité 1,N 0,N CLIENT Réf. client Nom Prénom Adresse COMMANDE Num. commande Date Montant PRODUIT Réf. produit Libellé Prix unitaire

Passons en revue les principes de la syntaxe. Ils ne devraient pas poser trop de problèmes.

La première ligne ne fait pas partie de la définition du MCD. Sous Jupyter Notebook, elle dénote l'appel à une « commande magique », qui lance Mocodo sur le reste de la cellule. En dehors d'un notebook, vous n'en avez pas besoin, et toute ligne commençant par un pourcentage (%) sera considérée comme un commentaire.

Une entité est définie par :

$$ \overbrace{\texttt{COMMANDE}}^{\text{son nom}} \quad \overbrace{\texttt{:}}^{\text{deux-points}} \quad \overbrace{\texttt{Num. commande, Date, Montant}}^{\text{ses attributs séparés par des virgules}} $$

Notez que le premier attribut d'une entité est considéré par défaut comme son identifiant, et donc souligné.

Une association est définie par :

$$ \overbrace{\texttt{INCLURE}}^{\text{son nom}} \quad \overbrace{\texttt{,}}^{\text{une virgule}} \quad \overbrace{ \underbrace{\texttt{1N}}_{\text{cardinalités}} \underbrace{\texttt{COMMANDE}}_{\text{entité}} \quad , \quad \underbrace{\texttt{0N}}_{\text{cardinalités}} \underbrace{\texttt{PRODUIT}}_{\text{entité}} }^{\text{ses pattes séparées par des virgules}} \quad \overbrace{\texttt{:}}^{\text{deux-points}} \quad \overbrace{\texttt{Quantité}}^{\text{ses attributs séparés par des virgules}} $$

Notez que pour les associations sans attributs (comme PASSER), le deux-points est facultatif.

Astuce. Si vous recopiez un MCD ou que vous l'avez bien en tête, commencez par les associations et, à tout moment, faites apparaître les entités manquantes (double clic sur le lapin magique sous Mocodo online). Elles auront comme identifiant le nom de l'entité en minuscules, par défaut précédé de « id. » (sauf pour les entités DATE et PÉRIODE). Vous n'aurez plus qu'à remplir les autres attributs :

In [13]:
%%mocodo -t guess:entities
Réserver, 1N Client, 1N Chambre, 0N Date: Durée
Réserver Durée 1,N 1,N 0,N Date date Chambre id. chambre Client id. client

sandbox.mcd
%%mocodo 
Réserver, 1N Client, 1N Chambre, 0N Date: Durée

Date: date
Chambre: id. chambre, 
Client: id. client, 

Dépendances fonctionnelles entre entités

Lorsque l'une des cardinalités maximales d'une association binaire est 1 (ou quelquefois 0), on désigne cette association sous le nom de dépendance fonctionnelle. On la figure souvent par un cercle portant le symbole DF : cela évite de se creuser la tête pour trouver un nom à une association qui (spoiler) disparaîtra corps et biens au moment du passage au relationnel.

In [14]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
DF, 0N CLIENT, 11 COMMANDE
COMMANDE: Num. commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
DF 0,N 1,1 INCLURE Quantité 1,N 0,N CLIENT Réf. client Nom Prénom Adresse COMMANDE Num. commande Date Montant PRODUIT Réf. produit Libellé Prix unitaire

Associations réflexives

Quelquefois appelées circulaires, unaires ou récursives, elles associent une entité à elle-même. Voici par exemple une représentation des filiations patrilinéaires (le 01 permet d'« arrêter » la remontée des ancêtres) :

In [15]:
%%mocodo
HOMME: Num. SS, Nom, Prénom
ENGENDRER, 0N HOMME, 01 HOMME
ENGENDRER 0,N 0,1 HOMME Num. SS Nom Prénom

Identifiants composites

Préfixez d'un tiret bas (_) les second, troisième, etc. attributs pour les inclure dans l'identifiant.

In [16]:
%%mocodo
GRATTE-CIEL: latitude, _longitude, nom, hauteur, année de construction
GRATTE-CIEL latitude longitude nom hauteur année de construction

Flèches sur les pattes

Suffixez d'un chevron (< ou >) les cardinalités de la patte concernée. La direction indiquée se lit en partant de l'association et en allant vers l'entité.

In [17]:
%%mocodo
Peut recevoir, 1N> Groupe sanguin, 1N< Groupe sanguin
Groupe sanguin: type de sang
Appartient, 11> Personne, 0N Groupe sanguin
Personne: Num. SS, Nom, Prénom, Sexe
Engendre, 0N< Personne, 22> Personne
Peut recevoir 1,N 1,N Appartient 1,1 0,N Engendre 0,N 2,2 Groupe sanguin type de sang Personne Num. SS Nom Prénom Sexe

Types de données

Comme on l'a vu dans l'introduction, chaque attribut peut être assorti d'un type entre crochets, qui servira lors de la conversion en SQL. À partir de la version 4.0, Mocodo est capable de deviner le type des attributs usuels :

In [18]:
%%mocodo -t guess:types --select source
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: Num. commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire

sandbox.mcd
%%mocodo --select source
CLIENT: Réf. client [VARCHAR(8)], Nom [VARCHAR(255)], Prénom [VARCHAR(255)], Adresse [VARCHAR(30)]
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: Num. commande [VARCHAR(8)], Date [DATE], Montant [DECIMAL(10,2)]
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité [INTEGER]
PRODUIT: Réf. produit [VARCHAR(8)], Libellé [VARCHAR(50)], Prix unitaire [DECIMAL(10,2)]

Tracé d'un MCD : principes

Mocodo combine les avantages de l'approche diagram as code (comme PlantUML, Mermaid ou Graphviz), avec la liberté de positionnement offerte par les logiciels WYSIWYG (what you see is what you get).

Sa grande originalité est de se baser sur l'ordre et la séparation des lignes de la description pour définir une mise en page qui se révèle suffisante dans la majorité des cas.

Le pont aux ânes du langage Mocodo

Premier principe : les boîtes (entités et associations) définies sur des lignes consécutives sont tracées sur une seule rangée.

Si l'on écrit les définitions sur des lignes consécutives, on se retrouve donc vite avec des chevauchements qui ne sautent pas forcément aux yeux :

In [19]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
COMMANDE: Num. commande, Date, Montant
PRODUIT: Réf. produit, Libellé, Prix unitaire
PASSER, 0N CLIENT, 11 COMMANDE
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PASSER 0,N 1,1 INCLURE Quantité 1,N 0,N CLIENT Réf. client Nom Prénom Adresse COMMANDE Num. commande Date Montant PRODUIT Réf. produit Libellé Prix unitaire

L'option --detect_overlaps (active par défaut sous Mocodo online) signale le problème et donne la solution :

In [20]:
%mocodo -i sandbox --detect_overlaps
Mocodo Err.29 - Mauvaise disposition des boîtes :
  - La patte « INCLURE — COMMANDE » chevauche « PRODUIT ».
  - La patte « INCLURE — PRODUIT » chevauche « PASSER ».
  - La patte « PASSER — CLIENT » chevauche « COMMANDE ».
  - Les pattes  « PASSER — COMMANDE » et « INCLURE — COMMANDE » se chevauchent.
Pour corriger cela, réordonnez et/ou sautez des lignes dans le texte-source, soit à la
main, soit à l'aide de l'option -t arrange (tablette de chocolat sous Mocodo online).

Limitation. Seuls les chevauchements mettant en jeu des pattes horizontales ou verticales sont détectés.

MCD sur plusieurs lignes

Deuxième principe : pour commencer une nouvelle rangée, il faut sauter une ligne :

In [21]:
%%mocodo
SCELERISQUE LOREM: blandit, elit, ligula
EROS, 11 SCELERISQUE LOREM, 1N PELLENTESQUE IPSUM: metus, congue

NIBH, 1N SCELERISQUE LOREM, 11 PELLENTESQUE IPSUM
PELLENTESQUE IPSUM: tincidunt, bibendum, consequat, integer
EROS metus congue 1,1 1,N NIBH 1,N 1,1 SCELERISQUE LOREM blandit elit ligula PELLENTESQUE IPSUM tincidunt bibendum consequat integer

Les centres des boîtes sont placés aux intersections d'une grille invisible. Ils sont donc alignés aussi bien horizontalement que verticalement. De plus, dans un but esthétique, le dessin fait l'objet d'une compression dans les deux dimensions. Par exemple, ci-dessus, un espace horizontal négatif a été créé entre le bord droit de l'entité de gauche et le bord gauche de l'entité de droite.

Mise en miroir

Mocodo permet de calculer facilement les symétriques d'un MCD :

  • verticalement : -t flip:v ;
  • horizontalement : -t flip:h ;
  • selon la seconde diagonale (transposition) : -t flip:d.
  • selon la première diagonale (transposition) : -t flip:vhd.
In [22]:
%mocodo -i sandbox --select mcd -t flip:h
EROS metus congue 1,1 1,N NIBH 1,N 1,1 SCELERISQUE LOREM blandit elit ligula PELLENTESQUE IPSUM tincidunt bibendum consequat integer

Corrections de la version 4.0.

  • Les sens de « horizontal » et « vertical » sont permutés pour être plus conformes à l'intuition.
  • La documentation parlait de première diagonale, c'était la seconde, et vice-versa.

Astuce. Transposez le MCD temporairement pour réaliser plus facilement certaines opérations d'édition en colonne, en particulier sous Mocodo online.

Insertion d'espacements

Mocodo centre les rangées qui contiennent moins de boîtes que les autres. Ce comportement n'est pas toujours idéal :

In [23]:
%%mocodo 
Ultrices, 01 Aliquet, 0N Aliquet
Aliquet: hendrerit, metus, lacus, quis
Risus, 1N Aliquet, 0N Massa
Massa: metus, posuere
Euismod, 0N Massa, 0N Massa

Convallis, 0N Aliquet, 0N Ante: vestibulum
Tincidunt, 11 Ante, 0N Massa

Gravida: ornare
Rutrum, 0N Gravida, 0N Ante, 0N Aliquet: faucibus, curae
Ante: vitae, tempor
Ultrices 0,1 0,N Risus 1,N 0,N Euismod 0,N 0,N Convallis vestibulum 0,N 0,N Tincidunt 1,1 0,N Rutrum faucibus curae 0,N 0,N 0,N Aliquet hendrerit metus lacus quis Massa metus posuere Gravida ornare Ante vitae tempor

L'utilisateur peut alors spécifier les espacements qu'il désire en complétant les rangées par des boîtes invisibles dont le seul rôle est de « pousser » les autres à l'emplacement voulu. Cela se fait en insérant manuellement des lignes réduites au caractère deux-points :

In [24]:
%%mocodo
Ultrices, 01 Aliquet, 0N Aliquet
Aliquet: hendrerit, metus, lacus, quis
Risus, 1N Aliquet, 0N Massa
Massa: metus, posuere
Euismod, 0N Massa, 0N Massa

:
:
Convallis, 0N Aliquet, 0N Ante: vestibulum
Tincidunt, 11 Ante, 0N Massa

Gravida: ornare
Rutrum, 0N Gravida, 0N Ante, 0N Aliquet: faucibus, curae
:
Ante: vitae, tempor
Ultrices 0,1 0,N Risus 1,N 0,N Euismod 0,N 0,N Convallis vestibulum 0,N 0,N Tincidunt 1,1 0,N Rutrum faucibus curae 0,N 0,N 0,N Aliquet hendrerit metus lacus quis Massa metus posuere Gravida ornare Ante vitae tempor

Réarrangement automatique

Cependant, en général, ces manipulations sont inutiles : Mocodo est capable de calculer tout seul des plongements à la fois compacts et esthétiques. Voici une compilation des réarrangements automatiques du MCD précédent produits par :

%mocodo -i sandbox -t arrange --seed 1
%mocodo -i sandbox -t arrange --seed 2
%mocodo -i sandbox -t arrange --seed 3
%mocodo -i sandbox -t arrange --seed 4
In [25]:
%mocodo -i ../examples/four_random_layouts --scale 0.8
Tincidunt 1,1 0,N Euismod 0,N 0,N Convallis vestibulum 0,N 0,N Risus 1,N 0,N Euismod 0,N 0,N Risus 1,N 0,N Rutrum faucibus curae 0,N 0,N 0,N Ultrices 0,1 0,N Convallis vestibulum 0,N 0,N Tincidunt 1,1 0,N Ultrices 0,1 0,N Rutrum faucibus curae 0,N 0,N 0,N Ultrices 0,1 0,N Risus 1,N 0,N Risus 1,N 0,N Ultrices 0,1 0,N Rutrum faucibus curae 0,N 0,N 0,N Convallis vestibulum 0,N 0,N Euismod 0,N 0,N Euismod 0,N 0,N Convallis vestibulum 0,N 0,N Rutrum faucibus curae 0,N 0,N 0,N Tincidunt 1,1 0,N Tincidunt 1,1 0,N Massa metus posuere Ante vitae tempor Massa metus posuere Aliquet hendrerit metus lacus quis Gravida ornare Aliquet hendrerit metus lacus quis Gravida ornare Ante vitae tempor Aliquet hendrerit metus lacus quis Aliquet hendrerit metus lacus quis Massa metus posuere Massa metus posuere Gravida ornare Gravida ornare Ante vitae tempor Ante vitae tempor

Extensions du modèle

Entité faible (ou identification relative)

Préfixez d'un tiret bas (_) une cardinalité 11 pour indiquer que l'entité distinguée est faible.

In [26]:
%%mocodo
ŒUVRE: Cote œuvre, Titre, Date parution
DF, 1N ŒUVRE, _11 EXEMPLAIRE
EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat
DF 1,N 1,1 ŒUVRE Cote œuvre Titre Date parution EXEMPLAIRE Num. exemplaire État du livre Date d’achat

Dans le diagramme, les identifiants (ou plutôt, discriminateurs) d'une telle entité seront soulignés en pointillés, tandis que le 11 sera par défaut souligné d'un trait plein.

Notez qu'un discriminateur n'est pas toujours obligatoire :

In [27]:
%%mocodo 
Employé: Num. employé, Nom employé, Prénom employé
Df, _11 Conjoint, 01 Employé
Conjoint: _Nom conjoint, Prénom conjoint
DF 1,1 0,1 Employé Num. employé Nom employé Prénom employé Conjoint Nom conjoint Prénom conjoint

Son absence implique cependant que l'occurrence de l'entité forte qui « renforce » une occurrence de l'entité faible ne peut en renforcer une autre : d'où la cardinalité maximale 1 sur la patte distinguant EMPLOYÉ.

Mocodo rejettera donc la version « polygame » du MCD précédent (avec 0N à la place de 01) :

In [28]:
%%mocodo
Employé: Num. employé, Nom employé, Prénom employé
Df, _11 Conjoint, 0N Employé
Conjoint: _Nom conjoint, Prénom conjoint
Mocodo Err.50 - L'entité faible « CONJOINT » devrait avoir un discriminateur.

Héritage (généralisation / spécialisation)

L'héritage permet de regrouper dans une entité, dite « mère », les attributs communs à plusieurs autres entités, dites « filles », qui se distinguent les unes des autres par des attributs spécifiques.

Pour définir une spécialisation, insérez une ligne spécifiant :

$$ \overbrace{\texttt{/}\,\texttt{XT}\,\texttt{\\}}^{\text{sa nature entre barres obliques}} \qquad \overbrace{\texttt{<}\,\texttt{-}}^{\text{son type de flèche}} \qquad \overbrace{\texttt{mère}}^{\text{une entité}} \qquad \overbrace{\texttt{,}}^{\text{une virgule}} \qquad \overbrace{\texttt{fille 1, fille 2, fille 3}}^{\text{des entités séparées par des virgules}} \qquad \overbrace{\texttt{: discriminateur}}^{\text{optionnellement, un attribut}} $$

In [29]:
%%mocodo
Personne: num SS, nom, prénom

/XT\ Personne <- Homme, Femme: sexe

Homme: 
:
Femme: nom de jeune fille
XT Personne num SS nom prénom Homme Femme nom de jeune fille

Inscrivez dans le triangle les symboles de votre choix pour prendre une part active aux guerres culturelles de notre temps :

Totalité Exclusion Symboles Exemple de population Toute personne est :
oui oui /XT\ ♂♂♂♂♂♂♂
♀♀♀♀♀♀♀♀♀♀
- soit un homme
- soit une femme
non oui /X\ ♂♂♂♂♂♂♂♂
♀♀♀♀♀♀
○○○○
- soit un homme
- soit une femme
- soit aucun des deux
oui non /T\ ♂♂♂♂♂♂
♀♀♀♀♀♀♀♀
⚥⚥⚥⚥
- soit un homme
- soit une femme
- soit les deux à la fois
non non /\ ♂♂♂♂♂
♀♀♀♀♀♀
○○○○
⚥⚥⚥⚥
- soit un homme
- soit une femme
- soit aucun des deux
- soit les deux à la fois

Contrainte inter-associations

Pour définir une telle contrainte, ajoutez n'importe où une ligne spécifiant :

$$ \overbrace{\texttt{(}\,\texttt{FOO}\,\texttt{)}}^{\text{son nom entre parenthèses}} \quad \overbrace{ \texttt{-}\,\texttt{>} \texttt{boîte 1,} \quad \texttt{.}\,\texttt{.} \texttt{boîte 2,} \quad \texttt{-}\,\texttt{-} \texttt{boîte 3,} \quad \texttt{boîte 4} }^{\text{les types de liens et les boîtes qu'elle met en jeu, séparés par des virgules}} \quad \overbrace{\texttt{:}\,\,\texttt{horizontale, verticale}}^{\text{optionnellement, ses coordonnées}} $$

Précisions.

  • Comme leur nom ne l'indique pas, ces contraintes peuvent aussi bien porter sur des entités que des associations.
  • Le nom d'une contrainte peut être formé de zéro à trois symboles quelconques.
  • Un lien est soit vide (trait invisible), soit formé d'un ou plusieurs symboles - (trait plein) ou . (trait pointillé), optionnellement précédés d'un symbole < (flèche vers la contrainte) et/ou suivis d'un symbole > (flèche vers la boîte).
  • Au contraire des boîtes (entités et associations), les contraintes ne sont pas... contraintes par la grille sous-jacente : la mise en page du MCD n'en tient absolument pas compte. Celui de l'exemple ci-dessous a donc dû être « aéré » avec des : pour leur faire de la place.
  • Les clauses de définition des contraintes peuvent apparaître n'importe où. Notez cependant que tout réarrangement automatique les enverra systématiquement à la fin du texte-source.
  • Chaque coordonnée du centre de la contrainte peut être exprimée sous la forme :
    • d'une référence à une boîte sur laquelle l'aligner horizontalement ou verticalement (respectivement) ;
    • d'un pourcentage de la largeur ou de la hauteur (respectivement) du MCD.
  • En l'absence de coordonnées, la contrainte est placée au barycentre des boîtes qu'elle relie.

Voici un exemple concret, adapté de la Fig. 7.37 de Merise, deuxième génération (Dominique Nanci et Bernard Espinasse, 4e éd., 2001) :

In [30]:
%%mocodo -t
:::
Dépôt: num dépôt, surface

:
Louer, 11 Commande, 0N Dépôt
:
Stocker, 1N Dépôt, 1N Article: quantité

Commande: num. commande, date
Composer, 1N Commande, 0N Article
:
Article: réf. article, prix

(I) ->Stocker, ..Dépôt, ..Article, --Composer, --Louer, Commande
I Louer 1,1 0,N Stocker quantité 1,N 1,N Composer 1,N 0,N Dépôt num dépôt surface Commande num. commande date Article réf. article prix
  • Article (réf. article, prix)
  • Commande (num. commande, date, #num dépôt)
  • Composer (_#num. commande_, _#réf. article_)
  • Dépôt (num dépôt, surface)
  • Stocker (_#num dépôt_, _#réf. article_, quantité)

Notez que pour Mocodo, ces contraintes sont purement décoratives : le passage au niveau relationnel ou physique n'en tient pas compte.

Agrégat (ou pseudo-entité)

Dans le MCD ci-dessous, le petit rond et l'enveloppe pointillée indiquent qu'une réservation d'une chambre donnée à une date donnée ne peut être faite que par un seul client :

In [31]:
%%mocodo --colors ocean # changement de palette pour faire apparaître un fond semi-transparent 
Date: Date
Réserver, /1N Client, 1N Chambre, 0N Date: Durée
Chambre: Num. chambre, Prix

Client: Id. client
Réserver Durée 1,N 1,N 0,N Date Date Chambre Num. chambre Prix Client Id. client

La syntaxe est minimale : une simple barre oblique / avant la cardinalité de l'entité-cible.

S'il y a au maximum deux entités à agréger, et que l'angle formé par l'association et les entités est plat ou rectangle, une enveloppe de points matérialise la pseudo-entité.

Sinon, pour des raisons de simplicité du code et de clarté du diagramme, l'enveloppe n'est pas affichée. Cependant, le petit rond subsiste et le reste des traitements est bien sûr inchangé.

Remarques.

  • La représentation traditionnelle demanderait à insérer une association DF entre CLIENT et RÉSERVER. Mais permettre l'association d'une entité et d'une association demanderait à apporter au code de Mocodo des changements conséquents, pour un bénéfice qui ne nous saute pas forcément aux yeux.
  • Les agrégats sur association binaire sont soit inutiles (sur une DF), soit impossibles (sur une non-DF, ils reviennent à permettre à une même occurrence d'entité de renforcer plusieurs occurrences d'une entité faible sans discriminateur). Mocodo les interdit dans les deux cas.

CIF à unicité complète

La notion d'agrégation n'a pas très bonne presse dans les milieux autorisés. Ceux-ci lui préfèrent généralement celle (équivalente) de contrainte d'intégrité fonctionnelle à unicité complète. Pour rentrer dans leurs bonnes grâces (et désactiver du même coup la visualisation de l'enveloppe et du petit rond), il suffit d'expliciter la contrainte correspondante dans le MCD précédent. Mocodo peut le faire pour vous :

In [32]:
%mocodo -i sandbox -t create:cifs arrange --seed=12 --colors ocean
CIF Réserver Durée 1,N 1,N 0,N Date Date Chambre Num. chambre Prix Client Id. client

sandbox.mcd
%%mocodo --seed=12 --colors ocean
Date: Date
Réserver, /1N Client, 1N Chambre, 0N Date: Durée
Chambre: Num. chambre, Prix

-INVISIBLE_1, XX Client, XX Client
Client: Id. client
:

(CIF) ..Réserver, ->Client, --Chambre, --Date: INVISIBLE_1, INVISIBLE_1

Remarquez que la visibilité de la CIF est assurée par le positionnement de celle-ci sur une boîte invisible introduite à cet effet : si vous rectifiez ce positionnement, vous pouvez bien sûr supprimer cette boîte.

Vous avez également le droit d'alléger la visualisation des CIFs complètes en transformant les traits pleins "--" des entités émettrices en traits invisibles "". Là encore, Mocodo peut le faire pour vous :

In [33]:
%mocodo -i sandbox -t create:cifs=light arrange --seed=12 --colors ocean
CIF Réserver Durée 1,N 1,N 0,N Date Date Chambre Num. chambre Prix Client Id. client

sandbox.mcd
%%mocodo --seed=12 --colors ocean
Date: Date
Réserver, /1N Client, 1N Chambre, 0N Date: Durée
Chambre: Num. chambre, Prix

-INVISIBLE_1, XX Client, XX Client
Client: Id. client
:

(CIF) ..Réserver, ->Client, Chambre, Date: INVISIBLE_1, INVISIBLE_1

Limitation. Au niveau fonctionnel, c'est toujours la barre oblique qui conditionne le traitement des CIF. Par conséquent, les CIF à unicité incomplète ne sont prises en charge qu'au niveau visuel.

Identifiants explicites dans les associations

Mocodo 4.1.1 relaxe par défaut (sauf dans la version en ligne) la contrainte de Merise restreignant aux entités la présence d'identifiants. Si vous l'osez, vous pouvez donc obtenir le même schéma relationnel avec le MCD « allégé » suivant :

In [34]:
%%mocodo -t
Client: Id. client
Réserver, 1N Client, 0N Chambre: _Date, Durée
Chambre: Num. chambre, Prix
Réserver Date Durée 1,N 0,N Client Id. client Chambre Num. chambre Prix
  • Chambre (Num. chambre, Prix)
  • Réserver (Id. client, _#Num. chambre_, Date, Durée)

L'introduction de cette possibilité, surtout destinée à simplifier le plongement des MCD touffus, est discutée ici.

Conversion d'un MCD

Passage au relationnel

Il se fait en deux étapes:

  • la création d'une représentation interne complète du MLD ;
  • la traduction de celle-ci en une représentation externe dans le ou les formats de sortie souhaités.

Pour construire la représentation interne, l'algorithme de base réalise la séquence d'opérations suivante :

  1. Pour chaque entité, une relation (table) de même nom et de mêmes attributs est créée. Le ou les identifiants de l'entité constituent la clé primaire de la relation.
  2. Toute relation issue d'une entité faible est renforcée, c'est-à-dire que la clé primaire de l'entité qu'elle détermine fonctionnellement vient s'adjoindre à sa clé primaire, au besoin de façon récursive.
  3. Les associations sont traitées ainsi :
    1. si toutes les pattes de l'association portent la cardinalité maximale N, une relation de même nom et de mêmes attributs est créée. Sa clé primaire est constituée de l'ensemble des clés primaires des relations issues des entités mises en jeu ;
    2. dans le cas contraire, c'est-à-dire si l'une des pattes de l'association porte la cardinalité (1,1), ou à défaut (0,1), l'entité distinguée se voit adjoindre :
      1. en tant que clés étrangères, l'ensemble des clés primaires des autres entités mises en jeu;
      2. en tant que simples attributs, l'ensemble des attributs de l'association.

Remarque. Un couple de cardinalités non standard, c'est-à-dire distinct de (0,1), (1,1), (0,N) et (1,N), est traité comme (0,1) si son deuxième symbole est un 1, et comme (0,N) sinon. Cela couvre en particulier les cas (*, 1), (*,N), (?,?) et (X,X).

Pour construire la représentation externe, Mocodo formate la représentation interne à l'aide d'un gabarit. Près d'une centaine de gabarits sont fournis, qui permettent de produire quatre grandes catégories de résultats :

  1. le schéma relationnel dans toutes les combinaisons de formats (HTML, Markdown, texte brut, $\LaTeX$) et d'options (avec ou sans explications, avec ou sans boilerplate, avec ou sans visualisation des contraintes d'unicité et d'optionalité) ;
  2. le diagramme relationnel au format Mocodo, avec ou sans visualisation des contraintes d'unicité et d'optionalité, ou dans des formats externes, comme DBML ou D2.
  3. le DDL en SQL ANSI et dans les principaux dialectes (Microsoft SQL Server, MySQL, Oracle DB, PostgreSQL, SQLite), avec ou sans boilerplate de création de la base ;
  4. le graphe des dépendances.

Niveau logique

Schéma relationnel

La transformation -t mld opère la conversion d'un MCD (modèle conceptuel de données) en un MLD (modèle logique de données), autrement appelé schéma relationnel :

In [36]:
%mocodo -i ccp -t mld

ccp_mld.md
  • Client (Réf. client, Nom, Prénom, Adresse)
  • Commande (Num. commande, Date, Montant, #Réf. client)
  • Inclure (_#Num. commande_, _#Réf. produit_, Quantité)
  • Produit (Réf. produit, Libellé, Prix unitaire)

Sous Jupyter Notebook, comme pour toutes les opérations de conversion, le tracé du MCD est omis par défaut. Dans le cas très fréquent où l'on a besoin de visualiser simultanément le MCD et le MLD, on peut invoquer l'option -t sans arguments (ou encore --mld) :

In [37]:
%mocodo -i ccp -t
Passer 0,N 1,1 Inclure Quantité 1,N 0,N Client Réf. client Nom Prénom Adresse Commande Num. commande Date Montant Produit Réf. produit Libellé Prix unitaire
  • Client (Réf. client, Nom, Prénom, Adresse)
  • Commande (Num. commande, Date, Montant, #Réf. client)
  • Inclure (_#Num. commande_, _#Réf. produit_, Quantité)
  • Produit (Réf. produit, Libellé, Prix unitaire)

Diagramme relationnel

La plupart des SGBD offrent une représentation hybride (graphique / texte) de la base sous la forme de tables liées par des flèches. Nous l'appelons diagramme relationnel. Sous Mocodo :

In [38]:
%mocodo -i ccp --colors mondrian -t diagram

ccp_mld.svg

Le nom du fichier généré avant rendu graphique se termine par _mld.mcd. L'extension .mcd signifie que Mocodo peut le prendre comme texte-source (bien que ce ne soit pas un schéma conceptuel). Examinons son contenu :

In [39]:
display.Code("ccp_mld.mcd", language="text")
Out[39]:
%%mocodo
:
Client: Réf. client, Nom, Prénom, Adresse
:
Commande: Num. commande, Date, Montant, #Réf. client > Client > Réf. client
:
Inclure: #Num. commande > Commande > Num. commande, _#Réf. produit > Produit > Réf. produit, Quantité
:
Produit: Réf. produit, Libellé, Prix unitaire
:

La syntaxe d'un MLD est effectivement la même que celle d'un MCD, à ceci près que les associations sont remplacées par des liens allant de l'attribut a1 de l'entité E1 à l'attribut a2 de l'entité E2, et notés : E1: ... a1 > E2 > a2.

Les relations sont placées dans le même ordre que les boîtes du MCD d'origine. Vous devrez quelquefois les réarranger (automatiquement ou manuellement) pour obtenir un résultat plus esthétique. Notez que des boîtes invisibles ont été automatiquement insérées une colonne sur deux afin de laisser de la place aux flèches.

Limitation. Les clés étrangères composites sont actuellement représentées comme si elles étaient séparées (autant de flèches que de parties).

Nouveautés de la version 4.0.

  • Ce qui se notait E1: ... a1->E2->a2 se note maintenant E1: ... a1 > E2 > a2.
  • Sous Jupyter Notebook, un seule étape suffit pour visualiser le diagramme relationnel.
  • Le nom du fichier intermédiaire se termine par _mld.mcd au lieu de .mld. L'ancienne extension est abandonnée.

Niveau physique : DDL

SQL

La principale raison de vivre d'un MCD est de se métamorphoser in fine en une chatoyante base de données relationnelles. Cela se fait au moyen d'un sous-ensemble du langage SQL appelé DDL (Data Definition Language). Sous Mocodo :

In [40]:
%mocodo -i ccp -t sql

ccp_ddl.sql
CREATE TABLE Client (
  PRIMARY KEY (Ref_client),
  Ref_client VARCHAR(8) NOT NULL,
  Nom        VARCHAR(255),
  Prenom     VARCHAR(255),
  Adresse    VARCHAR(255)
);

CREATE TABLE Commande (
  PRIMARY KEY (Num_commande),
  Num_commande VARCHAR(8) NOT NULL,
  Date         DATE,
  Montant      DECIMAL(10,2),
  Ref_client   VARCHAR(8) NOT NULL
);

CREATE TABLE Inclure (
  PRIMARY KEY (Num_commande, Ref_produit),
  Num_commande VARCHAR(8) NOT NULL,
  Ref_produit  VARCHAR(8) NOT NULL,
  Quantite     INTEGER
);

CREATE TABLE Produit (
  PRIMARY KEY (Ref_produit),
  Ref_produit   VARCHAR(8) NOT NULL,
  Libelle       VARCHAR(50),
  Prix_unitaire DECIMAL(10,2)
);

ALTER TABLE Commande ADD FOREIGN KEY (Ref_client) REFERENCES Client (Ref_client);

ALTER TABLE Inclure ADD FOREIGN KEY (Ref_produit) REFERENCES Produit (Ref_produit);
ALTER TABLE Inclure ADD FOREIGN KEY (Num_commande) REFERENCES Commande (Num_commande);

Notez le NOT NULL des clés primaires. Il s'agit d'une redondance, mais aussi d'une bonne pratique. Non seulement parce qu'explicit is better than implicit : elle peut se révéler utile, par exemple pour désactiver les contraintes de clé primaire pendant une maintenance tout en continuant à interdire le remplissage avec des NULL. Si cela vous gêne, nous montrons en annexe comment l'éliminer.

Principales nouveautés de la version 4.0.

  • Génération automatique des contraintes UNIQUE, NOT NULL et NULL appropriées.
  • Les libellés sont convertis en ASCII, et toute suite de caractères qui ne sont ni des lettres, ni des chiffres, ni des tirets bas sont remplacés par un unique tiret bas. Cela simplifie la référence aux tables et aux champs, et évite de noyer le DDL sous un essaim de délimiteurs (qui plus est spécifiques à chaque dialecte). Ainsi, « Réf. client » se trouvera transformé en Ref_client.
  • Vos choix de casse (minuscules, MAJUSCULES, _snakecase, camelCase, PascalCase, etc.) sont respectés.

Inférence de type

Avec l'option de réécriture -t create:types Mocodo essaiera d'inférer des libellés des attributs tout type manquant. La langue définie avec l'option --language est prioritaire, mais l'anglais prend la relève en cas d'échec.

In [41]:
%%mocodo -t create:types --select rw
Customer: Customer ID, Last Name, First Name, Address
Make Order, 0N Customer, 11 Order
Order: Order Number, Date, Amount
INCLUDE, 1N Order, 0N Product: Quantity
Product: Product ID, Description, Unit Price

sandbox.mcd
%%mocodo --select rw
Customer: Customer ID [VARCHAR(8)], Last Name [VARCHAR(255)], First Name [VARCHAR(255)], Address [VARCHAR(30)]
Make Order, 0N Customer, 11 Order
Order: Order Number [VARCHAR(8)], Date [DATE], Amount [DECIMAL(10,2)]
INCLUDE, 1N Order, 0N Product: Quantity [INTEGER]
Product: Product ID [VARCHAR(8)], Description [TEXT], Unit Price [DECIMAL(10,2)]

Il va de soi que les types inférés devront être systématiquement contrôlés, et parfois corrigés ou complétés. Une discussion sur StackOverflow, Common MySQL fields and their appropriate data types, a servi de point de départ. La liste des types utilisée est celle de Wikipedia. Consultez les correspondances spécifiées dans mocodo/resources/default_datatypes_fr.tsv, etc. pour plus de détails, et n'hésitez pas à ouvrir le débat si vous avez des corrections ou des suggestions.

Si vous préférez tout typer à la main, vous pouvez au moins créer les « cases » à remplir :

In [42]:
%%mocodo -t create:types=[] --select rw
Customer: Customer ID, Last Name, First Name, Address
Make Order, 0N Customer, 11 Order
Order: Order Number, Date, Amount
INCLUDE, 1N Order, 0N Product: Quantity
Product: Product ID, Description, Unit Price

sandbox.mcd
%%mocodo --select rw
Customer: Customer ID [], Last Name [], First Name [], Address []
Make Order, 0N Customer, 11 Order
Order: Order Number [], Date [], Amount []
INCLUDE, 1N Order, 0N Product: Quantity []
Product: Product ID [], Description [], Unit Price []

Dialectes de SQL

L'argument sql peut être remplacé par un nom de dialecte parmi mysql, oracle, postgresql, sqlite et (nouveauté de la version 4) mssql. Quelques transformations seront alors appliquées au code-source généré. Du fait de l'uniformisation de la syntaxe apportée par la version 4, elles sont assez minimes.

Notez les points suivants :

  • Mocodo ne touche pas aux types spécifiés par l'utilisateur. Une traduction inter-dialectes automatique est envisageable dans le futur, mais c'est un problème qui n'a en réalité aucune solution satisfaisante.
  • Mocodo protège les noms de tables ou de colonnes qui se trouveraient faire partie des mots réservés par le dialecte-cible. Par exemple, ci-dessous, les noms USER et MEMBER sont réservés en MySQL. Les listes viennent du site modern-sql.com de Markus Winand, et plus précisément de la page https://modern-sql.com/reserved-words-empirical-list.
  • Avec la sous-sous-option b, un boilerplate de création de la base est ajouté en préambule.
In [43]:
%%mocodo -t mysql:b
USER: username, mail, member

sandbox_ddl_mysql.sql
CREATE DATABASE IF NOT EXISTS `MCD`
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_general_ci
;
USE `MCD`;

CREATE TABLE `USER` (
  PRIMARY KEY (username  ),
  username   VARCHAR(42) NOT NULL,
  mail       VARCHAR(42),
  `member`   VARCHAR(42)
);

Notes sur les règles de passage

Génération de contraintes d'optionalité et d'unicité

Avec la sous-sous-option c, Mocodo peut faire apparaître dès le niveau logique certaines contraintes du niveau physique. Les notations sont les suivantes :

Contrainte niveau logique niveau physique
non-optionalité attribut! NOT NULL
optionalité attribut? NULL
unicité attribut $^{u1\ u2...}$ UNIQUE

Par exemple, ci-dessous, la clé étrangère _#Réfclient est maintenant marquée comme non optionnelle :

In [44]:
%mocodo -i ccp -t mld:c

ccp_mld.md
  • Client (Réf. client, Nom, Prénom, Adresse)
  • Commande (Num. commande, Date, Montant, #Réf. client!)
  • Inclure (_#Num. commande_, _#Réf. produit_, Quantité)
  • Produit (Réf. produit, Libellé, Prix unitaire)

La clé étrangère #id entreprise est marquée comme optionnelle :

In [45]:
%%mocodo --select all -t mld:c
Entreprise: id. entreprise, raison, activité, adresse
Envoyer, 0N Entreprise, 01 Participant
Participant: id. inscrit, nom, adresse
Envoyer 0,N 0,1 Entreprise id. entreprise raison activité adresse Participant id. inscrit nom adresse

sandbox_mld.md
  • Entreprise (id. entreprise, raison, activité, adresse)
  • Participant (id. inscrit, nom, adresse, #id. entreprise?)

La clé étrangère #id employé est marquée comme unique :

In [46]:
%%mocodo --select all -t mld:c
EMPLOYÉ: id. employé, nom employé
DIRIGER, 11 DÉPARTEMENT, 01 EMPLOYÉ
DÉPARTEMENT: id. département, nom département
DIRIGER 1,1 0,1 EMPLOYÉ id. employé nom employé DÉPARTEMENT id. département nom département

sandbox_mld.md
  • DÉPARTEMENT (id. département, nom département, #id. employé! u1)
  • EMPLOYÉ (id. employé, nom employé)

Ajout manuel de contraintes d'optionalité et d'unicité

Les contraintes NOT NULL ou NULL spécifiées dans les types peuvent également faire l'objet d'une visualisation au niveau relationnel :

In [47]:
%%mocodo -t mld:c
Personne: id. personne [VARCHAR(8)], nom [VARCHAR(255) NOT NULL], prénom [VARCHAR(255)], nom de jeune fille [VARCHAR(255) NULL]

sandbox_mld.md
  • Personne (id. personne, nom!, prénom, nom de jeune fille?)

Pour les contraintes d'unicité, qui peuvent s'appliquer à plusieurs groupes d'attributs potentiellement non disjoints, la notation est un peu plus complexe. Voici un exemple proposé par Fabien Duchateau :

In [48]:
%%mocodo --select all -t mld:c --shapes trebuchet # changement de police de caractères pour mieux distinguer les 1 des I
CLIENT: Réf. client, 1_Nom, 1_Prénom, Adresse, 2_Mail
CLIENT Réf. client ID Nom 1 Prénom 1 Adresse Mail 2

sandbox_mld.md
  • CLIENT (Réf. client, Nom u1, Prénom u1, Adresse, Mail u2)

C'est l'occasion d'introduire quelques définitions :

  • On appelle identifiant candidat d'une entité tout sous-ensemble minimal d'attributs dont chaque occurrence est unique.
  • Parmi ces sous-ensembles, l'un est élu identifiant (tout court), souligné, et appelé à devenir clé primaire lors du passage au relationnel.
  • Les candidats malheureux sont appelés identifiants alternatifs.

Ainsi, dans l'exemple précédent, l'ensemble des identifiants candidats de CLIENT est constitué de :

  • l'identifiant proprement dit Réf. client ;
  • l'identifiant alternatif (Nom, Prénom) (dont on supposera pour les besoins de la cause qu'il assure l'unicité) ;
  • l'identifiant alternatif Mail.

Par défaut, dès la première déclaration d'un identifiant alternatif, Mocodo fait apparaître une gouttière à gauche des attributs de toutes les entités. Y sont portés :

  • un symbole « ID » (resp. « id ») pour l'identifiant fort (resp. faible).
  • des chiffres de 1 à 9 correspondant aux numéros des identifiants alternatifs.

La notation de Mocodo permet de faire de n'importe quels sous-ensembles d'attributs des identifiants alternatifs. Ci-dessous, le premier identifiant alternatif est le triplet (bar, biz, quux), le second (biz, buz, quux) et le troisième (qux, quux) :

In [49]:
%%mocodo --select all -t markdown:c sql --shapes trebuchet
FOO: foo, 1_bar, 12_biz, 2_buz, 3_qux, 123_quux
FOO foo ID bar 1 biz 1 2 buz 2 qux 3 quux 1 2 3

sandbox_mld.md
  • FOO (foo, bar u1, biz u1 u2, buz u2, qux u3, quux u1 u2 u3)

sandbox_ddl.sql
CREATE TABLE FOO (
  PRIMARY KEY (foo),
  foo  VARCHAR(42) NOT NULL,
  bar  VARCHAR(42),
  biz  VARCHAR(42),
  buz  VARCHAR(42),
  qux  VARCHAR(42),
  quux VARCHAR(42),
  UNIQUE (bar, biz, quux),
  UNIQUE (biz, buz, quux),
  UNIQUE (qux, quux)
);

Examinons le cas exceptionnel où l'identifiant à souligner a un attribut commun avec un identifiant alternatif. Ce dernier devant être distinct et minimal, cela implique que l'identifiant est composite.

In [50]:
%%mocodo --shapes trebuchet
Entité 1_: 1_foo, _bar, 1_biz
Entité 2_: foo, 1_bar, 1_biz
Entité 3_: foo, 01_bar, 1_biz
Entité 1 foo 1 ID bar ID biz 1 Entité 2 foo ID bar 1 biz 1 Entité 3 foo ID bar 1 ID biz 1
  • Si l'attribut commun est en tête de liste (ici, foo, entité 1), rien ne change, on écrit 1_foo.
  • S'il n'est pas en tête de liste (ici, bar, entité 2), l'écriture 1_bar dénote déjà l'appartenance à un identifiant alternatif. Elle ne peut dénoter simultanément l'appartenance à l'identifiant à souligner.
  • C'est pourquoi on doit donc expliciter l'appartenance à l'identifiant à souligner qui, comme on l'a vu, est numéroté 0 (entité 3).

Un sous-cas demande encore réflexion : celui où le premier attribut ne fait pas partie de l'identifiant à souligner (entité 4). Si l'on veut alors que ce premier attribut appartienne à une clé alternative, il faut expliciter le 0 (entité 5).

In [51]:
%%mocodo --shapes trebuchet
Entité 40: _foo, _bar, biz
Entité 50: 01_foo, _bar, 1_biz
Entité 4 foo bar ID biz Entité 5 foo 1 bar ID biz 1

En résumé, on explicite le 0, soit pour empêcher le soulignement du premier attribut, soit pour forcer le soulignement d'un attribut suivant.

Cela devrait vous rappeler quelque chose… Remplacez 0 par _ dans la phrase précédente et vous retrouverez la règle que vous avez appris à connaître et à aimer : on explicite le _, soit pour empêcher le soulignement du premier attribut, soit pour forcer le soulignement d'un attribut suivant.

Gestion des entités faibles (identification relative)

Dans ce joli exemple dû à Idris NEUMANN, Initiation à la conception de bases de données relationnelles avec MERISE, les renforcements successifs aboutissent à faire entrer l'identifiant de RUE dans celui de APPARTEMENT, alors même que ces entités sont séparées par non moins de trois associations :

In [52]:
%%mocodo -t
Appartement: num appart., nb pièces
Composer, 0N Étage, _11 Appartement
Étage: num étage, nb appartements
Appartenir, 1N Immeuble, _11 Étage
Immeuble: num immeuble, nb étages
Se situer, 0N Rue, _11 Immeuble
Rue: code rue, nom rue
Composer 0,N 1,1 Appartenir 1,N 1,1 Se situer 0,N 1,1 Appartement num appart. nb pièces Étage num étage nb appartements Immeuble num immeuble nb étages Rue code rue nom rue
  • Appartement (_#code rue_, _#num immeuble_, _#num étage_, num appart., nb pièces)
  • Étage (_#code rue_, _#num immeuble_, num étage, nb appartements)
  • Immeuble (_#code rue_, num immeuble, nb étages)
  • Rue (code rue, nom rue)

Le résultat apparaît plus clairement sur le diagramme relationnel :

In [53]:
%mocodo -i sandbox -t diagram --colors mondrian

sandbox_mld.svg

Une phase préliminaire de l'algorithme de passage au relationnel consiste à « renforcer » les entités faibles de façon à traiter uniquement des identifiants forts dans la suite. Cela permet la gestion des renforcements en cascade comme ci-dessus, ainsi que la détection des problèmes de renforcement cyclique :

In [54]:
%%mocodo
Pick, 0N Land, _11 Peer
Land: true, hold

Peer: foot, city
Zone, 1N Peer, _11 Land
Pick 0,N 1,1 Zone 1,N 1,1 Land true hold Peer foot city
In [55]:
%mocodo -i sandbox -t
Mocodo Err.17 - Cycle d'entités faibles dans "Land", "Peer".

Gestion de l'héritage

La bonne gestion d'un héritage est primordiale, tant du point de vue de la préservation du patrimoine, que de l'optimisation des ressources financières, de la minimisation des conflits familiaux et du respect des dernières volontés du défunt. Je blague.

Adaptons ici un exemple d'un cours de Stéphane Crozat. Nous reprenons sa terminologie et donnons en parallèle celle introduite par Martin Fowler dans Patterns of Enterprise Application Architecture, Addison-Wesley (2003).

Ci-dessous, l'héritage est considéré comme total (tout document est soit un ouvrage, soit une thèse, soit les deux). Crozat passe en revue trois mécanismes possibles pour le passage au relationnel.


L'héritage par référence (en anglais, Class Table Inheritance ou Table Per Type Inheritance) se note en Mocodo par une flèche simple allant vers les filles. Une référence à la table-mère sera ajoutée dans chaque table-fille comme clé étrangère. L'intérêt de cette solution est en raison directe du nombre d'attributs non identifiants de l'entité-mère.

In [56]:
%%mocodo --select all -t mld:c
DOCUMENT: cote, titre, auteur
    
OUVRAGE: éditeur
/T\ DOCUMENT -> OUVRAGE, THÈSE
THÈSE: discipline, université
T DOCUMENT cote titre auteur OUVRAGE éditeur THÈSE discipline université

sandbox_mld.md
  • DOCUMENT (cote, titre, auteur)
  • OUVRAGE (_#cote_, éditeur)
  • THÈSE (_#cote_, discipline, université)

L'héritage par absorption dans les tables-filles (en anglais, Concrete Table Inheritance ou Table Per Concrete Inheritance) se note en doublant la flèche :

  1. les attributs de la table-mère sont reproduits dans chacune des filles. Pour chaque document qui est à la fois un ouvrage et une thèse, il y aura donc duplication des triplets (cote, titre, auteur).
  2. la table-mère disparaît. Pour éviter de perdre les informations sur les documents qui ne seraient ni des ouvrages, ni des thèses, Mocodo lève une erreur si l'héritage n'est pas total (T ou XT).
In [57]:
%%mocodo --select all -t mld:c
DOCUMENT: cote, titre, auteur
    
OUVRAGE: éditeur
/T\ DOCUMENT => OUVRAGE, THÈSE
THÈSE: discipline, université
T DOCUMENT cote titre auteur OUVRAGE éditeur THÈSE discipline université

sandbox_mld.md
  • OUVRAGE (cote, titre, auteur, éditeur)
  • THÈSE (cote, titre, auteur, discipline, université)

L'héritage par absorption dans la table-mère (en anglais, Single Table Inheritance ou Table Per Hierarchy Inheritance) se note par une flèche simple allant vers la mère. Les tables-filles disparaissent, et leurs attributs migrent dans la mère avec une contrainte d'optionalité (point d'interrogation en relationnel, NULL en SQL).

In [58]:
%%mocodo --select all -t mld:c sql
DOCUMENT: cote, titre, auteur

OUVRAGE: éditeur
/X\ DOCUMENT <- OUVRAGE, THÈSE: discriminateur [ENUM ('OUVRAGE', 'THÈSE')]
THÈSE: discipline, université
X DOCUMENT cote titre auteur OUVRAGE éditeur THÈSE discipline université

sandbox_mld.md
  • DOCUMENT (cote, titre, auteur, discriminateur?, éditeur?, discipline?, université?)

sandbox_ddl.sql
CREATE TABLE DOCUMENT (
  PRIMARY KEY (cote),
  cote           VARCHAR(42) NOT NULL,
  titre          VARCHAR(42),
  auteur         VARCHAR(42),
  discriminateur ENUM ('OUVRAGE', 'THÈSE') NULL,
  editeur        VARCHAR(42) NULL,
  discipline     VARCHAR(42) NULL,
  universite     VARCHAR(42) NULL
);

Ci-dessus, nous avons donné comme « attribut » au triangle d'héritage un « discriminateur » de type ENUM. Cela ajoute à la table un champ optionnel ou non (selon que l'héritage est partiel ou total) permettant de déterminer à quel type concret d'une occurrence on a affaire.

C'est par défaut un UNSIGNED INT, qui pourra prendre les valeurs :

  • 1 = OUVRAGE, 2 = THÈSE, pour l'héritage exclusif ;
  • 1 ($2^0$) = OUVRAGE, 2 ($2^1$) = THÈSE, 3 ($2^0 | 2^1$) = OUVRAGE + THÈSE, pour l'héritage non exclusif.

Alternativement à l'emploi d'un discriminateur, Mocodo peut ajouter un drapeau booléen par table-fille. Cela se note en doublant la flèche :

In [59]:
%%mocodo --select all -t mld:c sql
DOCUMENT: cote, titre, auteur

OUVRAGE: éditeur
/T\ DOCUMENT <= OUVRAGE, THÈSE
THÈSE: discipline, université
T DOCUMENT cote titre auteur OUVRAGE éditeur THÈSE discipline université

sandbox_mld.md
  • DOCUMENT (cote, titre, auteur, est ouvrage!, éditeur?, est these!, discipline?, université?)

sandbox_ddl.sql
CREATE TABLE DOCUMENT (
  PRIMARY KEY (cote),
  cote        VARCHAR(42) NOT NULL,
  titre       VARCHAR(42),
  auteur      VARCHAR(42),
  est_ouvrage BOOLEAN NOT NULL,
  editeur     VARCHAR(42) NULL,
  est_these   BOOLEAN NOT NULL,
  discipline  VARCHAR(42) NULL,
  universite  VARCHAR(42) NULL
);

Gestion de l'agrégation

Un agrégat simple autour d'une association dont toutes les cardinalités maximales sont N se traduit en relationnel comme la même association non agrégée, mais avec une clé primaire réduite :

In [60]:
%%mocodo --select all -t mld:c
DATE: date
RÉSERVER, /1N CLIENT, 1N CHAMBRE, 0N DATE: durée
CHAMBRE: num. chambre, prix

CLIENT: id. client, nom client
RÉSERVER durée 1,N 1,N 0,N DATE date CHAMBRE num. chambre prix CLIENT id. client nom client

sandbox_mld.md
  • CHAMBRE (num. chambre, prix)
  • CLIENT (id. client, nom client)
  • RÉSERVER (_#num. chambre_, date, #id. client!, durée)

Un agrégat simple autour d'une association dont la cardinalité maximale « de sortie » est 1 se traduit en relationnel comme la même association non agrégée, mais avec une contrainte d'unicité sur la clé étrangère. Ci-dessous, au lieu d'avoir simplement num résa $\implies$ (num voilier, num semaine), on a donc en plus (num voilier, num semaine) $\implies$ num résa :

In [61]:
%%mocodo --select all -t mld:c
Voilier: num voilier, longueur
Offrir, /11 Réservation, 0N Voilier, 0N Semaine: tarif
Semaine: num semaine, date début

Réservation: num résa, arrhes, date résa
Offrir tarif 1,1 0,N 0,N Voilier num voilier longueur Semaine num semaine date début Réservation num résa arrhes date résa

sandbox_mld.md
  • Réservation (num résa, arrhes, date résa, #num voilier! u1, #num semaine! u1, tarif)
  • Semaine (num semaine, date début)
  • Voilier (num voilier, longueur)

Le cas des agrégats multiples, plus rare, est étudié en annexe.

Ajustement des règles de passage

Supprimer ou maintenir une table facultative

Le passage au relationnel supprime automatiquement les tables réduites à une clé primaire, pourvu qu'aucun composant de celle-ci ne soit clé étrangère. Si l'on souhaite maintenir certaines de ces tables, on préfixe d'un + l'entité concernée. Ainsi, ci-dessous, Date est supprimée, mais pas Thème.

In [62]:
%%mocodo --select mld mcd -t mld:e
Animateur: num. animateur, nom animateur
Intervenir, 1N Animateur, 1N Formation, 1N Date: nb heures
Formation: id. formation, durée
Aborder, 1N Thème, 1N Formation
+Thème: thème

Date: date
:

sandbox_mld.md
  • Aborder (_#thème_, _#id. formation_)

    • Le champ thème fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Thème.
    • Le champ id. formation fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Formation.
  • Animateur (num. animateur, nom animateur)

    • Le champ num. animateur constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Animateur.
    • Le champ nom animateur était déjà un simple attribut de l'entité Animateur.
  • Formation (id. formation, durée)

    • Le champ id. formation constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Formation.
    • Le champ durée était déjà un simple attribut de l'entité Formation.
  • Intervenir (_#num. animateur_, _#id. formation_, date, nb heures)

    • Le champ num. animateur fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Animateur.
    • Le champ id. formation fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Formation.
    • Le champ date fait partie de la clé primaire de la table. Sa table d'origine (Date) ayant été supprimée, il n'est pas considéré comme clé étrangère.
    • Le champ nb heures était déjà un simple attribut de l'association Intervenir.
  • Thème (thème)

    • Le champ thème constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Thème.

NB. La table Date a été supprimée car elle était réduite à la clé primaire de son entité d'origine. Pour conserver de telles tables, préfixez d'un « + » la définition des entités d'origine.

Intervenir nb heures 1,N 1,N 1,N Aborder 1,N 1,N Animateur num. animateur nom animateur Formation id. formation durée Thème thème Date date

Notez l'explication de la suppression (en NB) et celle de la perte du caractère étranger de l'attribut date (dans la table Intervenir). Pour une discussion sur cette problématique, cf. issue #66.

Forcer une table pour éviter un champ optionnel

Une association de dépendance fonctionnelle ne donne normalement pas lieu à une création de table. Pour reprendre un exemple vu plus haut :

In [63]:
%%mocodo --select all -t mld:c
Entreprise: id. entreprise, raison, activité, adresse
Envoyer, 0N Entreprise, 01 Participant
Participant: id. inscrit, nom, adresse
Envoyer 0,N 0,1 Entreprise id. entreprise raison activité adresse Participant id. inscrit nom adresse

sandbox_mld.md
  • Entreprise (id. entreprise, raison, activité, adresse)
  • Participant (id. inscrit, nom, adresse, #id. entreprise?)

Dans le cas où les particuliers sont beaucoup plus nombreux que les employés d'entreprise, la clé étrangère #id. entreprise est presque toujours à NULL. C'est une perte d'espace de stockage. On peut entourer l'association de crochets droits préfixer d'un + (à partir de la version 4) l'association pour forcer sa conversion en table. Mocodo produit alors une visualisation intermédiaire entre entité et association :

In [64]:
%%mocodo --select all -t mld:c --colors mondrian
Entreprise: id. entreprise, raison, activité, adresse
+Envoyer, 0N Entreprise, 01 Participant
Participant: id. inscrit, nom, adresse
Envoyer 0,N 0,1 Entreprise id. entreprise raison activité adresse Participant id. inscrit nom adresse

sandbox_mld.md
  • Entreprise (id. entreprise, raison, activité, adresse)
  • Envoyer (_#id. inscrit_, #id. entreprise!)
  • Participant (id. inscrit, nom, adresse)

Cela permet du même coup d'éviter un champ optionnel, dont la gestion peut être délicate (notamment sous Microsoft SQL Server qui, au mépris du standard SQL, ne semble pas convaincu qu'une colonne UNIQUE peut contenir plus d'un NULL !).

Préciser le rôle d'une clé étrangère

Ce MCD modélise la soutenance de stage des étudiants, ainsi que la visite d'amitié et de contrôle dont les honore leur enseignant responsable :

In [65]:
%%mocodo -t
Soutenir, 01 Étudiant, 0N Date: note stage
Étudiant: num. étudiant, nom, coordonnées

Date: date
Répondre de, 0N Date, 11 Étudiant, 0N Enseignant
Enseignant: num. enseignant, nom, coordonnées
Soutenir note stage 0,1 0,N Répondre de 0,N 1,1 0,N Étudiant num. étudiant nom coordonnées Date date Enseignant num. enseignant nom coordonnées
  • Enseignant (num. enseignant, nom, coordonnées)
  • Étudiant (num. étudiant, nom, coordonnées, date 1, note stage, date 2, #num. enseignant)

Force est de constater que la table Étudiant laisse quelque peu à désirer du point de vue sémantique :

  • on ne sait pas à quoi correspondent les attributs date 1 et date 2 : ils ne peuvent en tout cas certainement pas être laissés en l'état ;
  • ensuite, on pourrait avoir envie d'expliciter la raison pour laquelle un enseignant apparaît parmi les attributs d'un étudiant.

Ces précisions peuvent être apportées en insérant, entre la cardinalité et l'entité des pattes appropriées, une note entre crochets, appelée rôle. Ces rôles seront utilisés pour compléter le nom des clés étrangères correspondantes. Cela permet de réintroduire la sémantique perdue lors de la disparition des associations de dépendance fonctionnelle par lesquelles elle ont migré :

In [66]:
%%mocodo -t mld
Soutenir, 01 Étudiant, 0N [soutenance] Date: note stage
Étudiant: num. étudiant, nom, coordonnées

Date: date
Répondre de, 0N [+ visite resp] Date, 11 Étudiant, 0N [-num. ens. resp.] Enseignant
Enseignant: num. enseignant, nom, coordonnées

sandbox_mld.md
  • Enseignant (num. enseignant, nom, coordonnées)
  • Étudiant (num. étudiant, nom, coordonnées, date soutenance, note stage, date visite resp, #num. ens. resp.)

La composition du rôle est entièrement paramétrable :

  • date soutenance : par défaut, le rôle est concaténé à la clé, avec un séparateur dépendant du gabarit (espace par défaut, tiret bas pour SQL).
  • date visite resp. : + en préfixe supprime le séparateur.
  • num. ens. resp. : - en préfixe supprime le nom de la clé et le remplace par le rôle.

Pour ne pas surcharger le dessin, le rôle n'est pas affiché à côté du lien, mais il apparaît au survol de la cardinalité.

Correction de la version 4.0. Dans une association réflexive hiérarchique, c'est désormais le rôle porté par la patte *N qui sert à rétablir la sémantique. Auparavant c'était l'inverse, en contradiction avec le traitement des associations binaires et n-aires : si vous avez utilisé des rôles dans une association réflexive avant la version 4.0.0, vous devez donc les permutez pour que Mocodo les traite correctement. Reprenons la filiation patrilinéaire :

In [67]:
%%mocodo -t
HOMME: num. SS, nom, prénom
ENGENDRER, 0N [père] HOMME, 01 [fils] HOMME
ENGENDRER 0,N 0,1 HOMME num. SS nom prénom
  • HOMME (num. SS, nom, prénom, #num. SS père)

Orienter la migration dans les DF à double sens

Lorsque toutes les cardinalités d'une dépendance fonctionnelle sont 11 (ou toutes 01), le sens de migration est spécifié à coût zéro en référençant l'entité réceptrice en tête de la liste des entités énumérées dans la clause de définition de l'association :

In [68]:
%%mocodo -t mld diagram sql --colors mondrian
USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)]
DF, 11 USER, 11 AUTHENTICATION
AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)]

sandbox_mld.md
  • AUTHENTICATION (email, password hash, salt)
  • USER (user id, name, pseudo, #email)

sandbox_mld.svg


sandbox_ddl.sql
CREATE TABLE AUTHENTICATION (
  PRIMARY KEY (email),
  email         VARCHAR(255) NOT NULL,
  password_hash BINARY(64),
  salt          BINARY(16)
);

CREATE TABLE USER (
  PRIMARY KEY (user_id),
  user_id VARCHAR(8) NOT NULL,
  name    VARCHAR(100),
  pseudo  VARCHAR(100),
  email   VARCHAR(255) NOT NULL,
  UNIQUE (email)
);

ALTER TABLE USER ADD FOREIGN KEY (email) REFERENCES AUTHENTICATION (email);

Dans la version avec identification relative, c'est l'entité faible qui doit être placée en tête :

In [69]:
%%mocodo -t mld diagram sql --colors mondrian
USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)]
DF, _11 AUTHENTICATION, 11 USER
AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)]

sandbox_mld.md
  • AUTHENTICATION (_#user id_, email, password hash, salt)
  • USER (user id, name, pseudo)

sandbox_mld.svg


sandbox_ddl.sql
CREATE TABLE AUTHENTICATION (
  PRIMARY KEY (user_id, email),
  user_id       VARCHAR(8) NOT NULL,
  email         VARCHAR(255) NOT NULL,
  password_hash BINARY(64),
  salt          BINARY(16)
);

CREATE TABLE USER (
  PRIMARY KEY (user_id),
  user_id VARCHAR(8) NOT NULL,
  name    VARCHAR(100),
  pseudo  VARCHAR(100)
);

ALTER TABLE AUTHENTICATION ADD FOREIGN KEY (user_id) REFERENCES USER (user_id);

Les traitements alternatifs (fusion en une seule table ou migration dans les deux sens) ne sont pas pris en charge par Mocodo. La dernière pratique ressortit à la phase d'optimisation et de dénormalisation de la base, qui est en dehors de sa juridiction. La seule chose que vous pouvez faire, à des fins d'illustration, est de reprendre le MLD généré pour y ajouter à la main la migration inverse. Notez cependant que les schémas logique et physique générés seront alors dépourvus de toute clé étrangère (et nécessiteront donc également d'être retouchés à la main).

In [70]:
%%mocodo -t mld sql --colors mondrian --select all
:
USER: user id [VARCHAR(8)], name [VARCHAR(100)], pseudo [VARCHAR(100)], #email > AUTHENTICATION > email
:
AUTHENTICATION: email [VARCHAR(255)], password hash [BINARY(64)], salt [BINARY(16)], #user id > USER > user id
:
USER user id name pseudo #email AUTHENTICATION email password hash salt #user id

sandbox_mld.md
  • AUTHENTICATION (email, password hash, salt, user id)
  • USER (user id, name, pseudo, email)

sandbox_ddl.sql
CREATE TABLE AUTHENTICATION (
  PRIMARY KEY (email),
  email         VARCHAR(255) NOT NULL,
  password_hash BINARY(64),
  salt          BINARY(16),
  user_id       VARCHAR(42)
);

CREATE TABLE USER (
  PRIMARY KEY (user_id),
  user_id VARCHAR(8) NOT NULL,
  name    VARCHAR(100),
  pseudo  VARCHAR(100),
  email   VARCHAR(42)
);

Autres sorties relationnelles

Graphe des dépendances

La table A dépend de la table B lorsque A possède une clé étrangère qui est clé primaire de B. Cette notion est utile dans le cas où l'on doit importer une base de données à partir d'un ensemble de fichiers CSV (ou autres). Si l'on veut éviter de perdre le bénéfice du contrôles de clés étrangères (en faisant, p. ex. sous MySQL, SET FOREIGN_KEY_CHECKS = 0), il conviendra de lire ces fichiers dans un ordre topologique quelconque. Mocodo peut générer un graphe des dépendances qui met cet ordre en évidence :

In [71]:
%mocodo -i ccp -t dependencies --defer

ccp_dependencies.svg

Même si un tel graphe n'est pas forcément sans circuits, remplir les tables dans le sens de lecture des langues latines minimisera le recours à la désactivation des contraintes de clés étrangères.

Diagramme relationnel / DDL BDML

D'après son site officiel :

DBML (Database Markup Language) est un DSL (langage dédié) open-source conçu pour définir et documenter les schémas et structures de base de données. Il vise la simplicité, la cohérence et la lisibilité.

Mocodo parle maintenant DBML :

In [72]:
%mocodo -i ccp -t dbml --title CCP

ccp_ddl.dbml
dbml
Table "Client" {
  "Réf. client" VARCHAR(8) [pk, NOT NULL]
  "Nom"         VARCHAR(255)
  "Prénom"      VARCHAR(255)
  "Adresse"     VARCHAR(255)
}

Table "Commande" {
  "Num. commande" VARCHAR(8) [pk, NOT NULL]
  "Date"          DATE
  "Montant"       DECIMAL(10,2)
  "Réf. client"   VARCHAR(8) [NOT NULL]
}

Table "Inclure" {
  "Num. commande" VARCHAR(8) [NOT NULL]
  "Réf. produit"  VARCHAR(8) [NOT NULL]
  "Quantité"      INTEGER
  Indexes {
    ("Num. commande", "Réf. produit") [pk]
  }
}

Table "Produit" {
  "Réf. produit"  VARCHAR(8) [pk, NOT NULL]
  "Libellé"       VARCHAR(50)
  "Prix unitaire" DECIMAL(10,2)
}

Ref:"Commande"."Réf. client" > "Client"."Réf. client"
Ref:"Inclure"."Num. commande" > "Commande"."Num. commande"
Ref:"Inclure"."Réf. produit" > "Produit"."Réf. produit"

À notre connaissance, il n'existe pas actuellement d'API publique de rendu des diagrammes DBML. Pour les visualiser, copiez-collez la sortie sur Dbdiagram.io, ou installez un plugin VS-Code :

In [73]:
display.SVG("../examples/dbml.svg")
Out[73]:
1*1**1CLIENTRéf. clientVARCHAR(8)NomVARCHAR(255)PrénomVARCHAR(255)AdresseVARCHAR(255)COMMANDENum. commandeVARCHAR(8)DateDATEMontantDECIMAL(10,2)Réf. clientVARCHAR(8)INCLURENum. commandeVARCHAR(8)Réf. produitVARCHAR(8)QuantitéINTEGERPRODUITRéf. produitVARCHAR(8)LibelléVARCHAR(50)Prix unitaireDECIMAL(10,2)

Diagramme relationnel D2

D2 est un langage de description de diagrammes de différents types. La prise en charge des diagrammes relationnels est minimale, mais le projet est jeune (actuellement en version 0.6.1, open source depuis novembre 2022). Son point fort est TALA, son algorithme de plongement propriétaire, que vous pouvez tester ici. Celui-ci requérant une licence payante, si vous déférez le rendu, c'est le plongement par défaut (Dagre, celui de Mermaid) qui sera utilisé.

In [74]:
%mocodo -i ccp -t d2

ccp_ddl.d2
d2
"Client": { shape: sql_table
  "Réf. client": VARCHAR(8) {constraint: PK}
  "Nom":         VARCHAR(255) 
  "Prénom":      VARCHAR(255) 
  "Adresse":     VARCHAR(255) 
}

"Commande": { shape: sql_table
  "Num. commande": VARCHAR(8) {constraint: PK}
  "Date":          DATE 
  "Montant":       DECIMAL(10,2) 
  "Réf. client":   VARCHAR(8) {constraint: [FK; NOT NULL]}
}

"Inclure": { shape: sql_table
  "Num. commande": VARCHAR(8) {constraint: [PK; FK]}
  "Réf. produit":  VARCHAR(8) {constraint: [PK; FK]}
  "Quantité":      INTEGER 
}

"Produit": { shape: sql_table
  "Réf. produit":  VARCHAR(8) {constraint: PK}
  "Libellé":       VARCHAR(50) 
  "Prix unitaire": DECIMAL(10,2) 
}

"Commande"."Réf. client" -> "Client"."Réf. client"
"Inclure"."Num. commande" -> "Commande"."Num. commande"
"Inclure"."Réf. produit" -> "Produit"."Réf. produit"
In [75]:
%mocodo -i ccp -t d2 --defer

ccp_ddl.svg

Autres conversions

Diagramme de classes UML

À tout seigneur tout honneur, Mocodo peut traduire votre MCD en UML. Ce formalisme graphique n'a, curieusement, pas de DSL textuel officiel. Nous nous rabattons donc sur le standard de fait, PlantUML :

In [76]:
%mocodo -i ccp --title CCP -t uml:plantuml=- # '-' supprime un préambule par défaut qui ne nous intéresse pas ici

ccp_uml.puml
puml
@startuml "CCP"

!define Table(x) class "x" << (T,#FFFFFF) >>
!define pk(x) <b>x</b>

Table("Client") {
    {field} + pk(Réf. client) VARCHAR(8)
    {field} + Nom         VARCHAR(255)
    {field} + Prénom      VARCHAR(255)
    {field} + Adresse     VARCHAR(255)
}

"Client" "1" --- "*" "Commande": "Passer"

Table("Commande") {
    {field} + pk(Num. commande) VARCHAR(8)
    {field} + Date          DATE
    {field} + Montant       DECIMAL(10,2)
}

"Commande" "*" --- "1..*" "Produit": "Inclure"
("Commande", "Produit") .. "Inclure"
Table("Inclure") {
    {field} + Quantité INTEGER
}

Table("Produit") {
    {field} + pk(Réf. produit)  VARCHAR(8)
    {field} + Libellé       VARCHAR(50)
    {field} + Prix unitaire DECIMAL(10,2)
}

@enduml
In [77]:
%mocodo -i ccp -t uml --defer --colors brewer+5

ccp_uml.svg

ERD avec la convention Look across

Nouveauté de la version 4.0. Force est de reconnaître que de nos jours, les MCD à la sauce Merise ne sont plus goûtés que par une poignée d'irréductibles Gaulois (et contractuellement leurs étudiants). Dans le cadre de son projet secret de domination planétaire, Mocodo commence à faire du pied à des notations mieux comprises du reste de l'univers.

Notation de Chen

Un MCD peut être converti en un ERD (Entity-Relationship Diagram) dans la notation de Chen, sans ses attributs ou avec :

In [78]:
%mocodo -i ccp -t chen --defer --colors ocean

ccp_erd_chen.svg

In [79]:
%mocodo -i ccp -t chen:attrs --defer --colors ocean

ccp_erd_chen.svg

Notation crow's foot

Dans le même ordre d'idées, Mocodo peut générer des ERD dans l'astucieuse notation introduite en 1976 par Gordon Everest. Par défaut, le format du fichier intermédiaire est là encore Graphviz :

In [80]:
%mocodo -i ccp -t crow --defer --colors brewer+3

ccp_erd_crow.svg

Il est également possible de demander une sortie au format Mermaid. Vous en avez un exemple dans l'introduction, nous ne le répétons pas ici. Le DSL de Mermaid est de plus haut niveau, non encombré d'informations de style. Cependant, le format Graphviz peut être préféré pour plusieurs raisons :

  • on peut lui appliquer une palette de couleurs de Mocodo (cf. ci-dessus) ;
  • il gère les accents ;
  • il admet la virgule dans les types (Mermaid demande actuellement à transformer DECIMAL(10,2) en DECIMAL(10-2)) ;
  • il peut produire de meilleurs plongements (notamment en jouant sur la valeur de l'option --seed) ;
  • ceux-ci peuvent-être rectifiés à la main (quoique péniblement).

Dictionnaire des données

Vous pouvez extraire sous forme de table diverses informations sur les attributs de votre MCD.

Un format possible est TSV. Dans ce cas, sous Jupyter Notebook, si la bibliothèque pandas est installée, elle sera rendue comme un dataframe :

In [81]:
%mocodo -i ccp -t data_dict:tsv

ccp_data_dict_3.tsv
  Entité ou association Libellé de l'attribut Type
0 Client Adresse VARCHAR(255)
1 Client Nom VARCHAR(255)
2 Client Prénom VARCHAR(255)
3 Client Réf. client VARCHAR(8)
4 Commande Date DATE
5 Commande Montant DECIMAL(10,2)
6 Commande Num. commande VARCHAR(8)
7 Inclure Quantité INTEGER
8 Produit Libellé VARCHAR(50)
9 Produit Prix unitaire DECIMAL(10,2)
10 Produit Réf. produit VARCHAR(8)

Le format par défaut est Markdown. Vous pouvez préciser en sous-sous-option tout ou partie des colonnes suivantes dans l'ordre où vous les souhaitez :

  • label: le libellé de l'attribut ;
  • type : son type ou un descriptif (auquel cas il conviendra de changer le nom de la colonne) ;
  • box : le nom de l'entité ou association où il se trouve.

Entourez ces noms de colonnes de balises Markdown pour les mettre en forme (pas d'incidence en TSV). Faites-les suivre de ="Nom de colonne personnalisé" pour éviter la valeur par défaut (dépendante de l'option language). Dans l'exemple ci-dessous, les sous-sous-options se décodent ainsi :

  • **box**="Entité ou association" : boîtes en colonne 1, en-tête personnalisé, cellules en gras ;
  • label : libellé des attributs en colonne 2 ;
  • `type`=`Type` : types en colonne 3, en-tête personnalisé et cellules dans une police non proportionnelle.
In [82]:
%mocodo -i ccp -t data_dict:**box**="Entité ou<br>association",label,`type`=`"Type de données"`

ccp_data_dict_3.md
Entité ou
association
Libellé de l'attribut Type de données
Client Adresse VARCHAR(255)
" Nom VARCHAR(255)
" Prénom VARCHAR(255)
" Réf. client VARCHAR(8)
Commande Date DATE
" Montant DECIMAL(10,2)
" Num. commande VARCHAR(8)
Inclure Quantité INTEGER
Produit Libellé VARCHAR(50)
" Prix unitaire DECIMAL(10,2)
" Réf. produit VARCHAR(8)

Aménités.

  • Au format Markdown, les répétitions de cellules de la première colonne sont remplacées par un guillemet itératif.
  • Le tableau est automatiquement trié selon sa première, puis éventuellement deuxième et troisième colonnes.
  • Si une seule colonne est demandée, la ligne d'en-tête n'est pas générée et, en Markdown, c'est une liste qui est produite.
In [83]:
%mocodo -i ccp -t data_dict:label

ccp_data_dict_1.md
  • Adresse
  • Date
  • Libellé
  • Montant
  • Nom
  • Num. commande
  • Prix unitaire
  • Prénom
  • Quantité
  • Réf. client
  • Réf. produit

Nouveautés de la version 4.0.

  • Sélection, ordre et nommage des colonnes, mise en forme Markdown, tri, guillemets itératifs.
  • Remplacement par un algorithme dédié du gabarit relationnel utilisé (abusivement) dans les versions antérieures.

URL de partage

Vous pouvez demander à encoder le texte-source de votre MCD dans un lien vers Mocodo online, qui le composera automatiquement dans la zone d'entrée :

In [84]:
%mocodo -i ccp -t share

ccp_url.url
https://www.mocodo.net/?mcd=eNptkMEKgkAQhu89xRwLJDQQwtuySgm5mEgX6bDlBgu6xrYLvZLP4Ys1ahZYt_m_Yeb_Z2glhTIBZF17W8N1UFCcSEb3JFtuV2cHWFN_ycb3e5bqrlV_OCm1eDzEjC9SjlA74DKgg4UDnge0qWuuSrGYigCYrTHFW85yhNwgCkkeoUgaZXgfNYxonJDD0nOdDTrF6lpZLXA_--wffFPdlFbipUeLc9J0LRQxy6NdlGG-qTm-4T7Kmf9BXkRV9XMT9t3xF_IJVknDpRY_gV4LRG5Z

Mocodo pour la pédagogie

Vue en extension

Un chiffre ou tiret bas à la fin du nom d'une boîte (entité ou association) est utilisé en interne pour distinguer cette boîte des autres, mais n'est pas affiché dans le diagramme conceptuel. Cela peut servir à produire une vue en extension d'un MCD.

Voici par exemple le MCD que j'utilise en cours pour introduire la notion d'entité faible (à gauche, vue en compréhension, à droite vue en extension):

In [85]:
%%mocodo
ŒUVRE1: cote, titre, date de publication
:::
ŒUVRE2: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975
:
  
DF, 1N ŒUVRE1, _11 EXEMPLAIRE1
::
DF, XX ŒUVRE2, XX EXEMPLAIRE2
DF, XX ŒUVRE2, XX EXEMPLAIRE3
DF, XX ŒUVRE2, XX EXEMPLAIRE4

EXEMPLAIRE1: numéro d'exemplaire, état, date d'achat
::
EXEMPLAIRE2: 1, bon état, 12/6/1975
EXEMPLAIRE3: 2, bon état, 1/8/1977
EXEMPLAIRE4: 3, reliure rongée, 3/4/2005
DF 1,N 1,1 DF DF DF ŒUVRE cote titre date de publication ŒUVRE 612.NAT.34 J’apprends à lire à mes souris blanches mai 1975 EXEMPLAIRE numéro d’exemplaire état date d’achat EXEMPLAIRE 1 bon état 12/6/1975 EXEMPLAIRE 2 bon état 1/8/1977 EXEMPLAIRE 3 reliure rongée 3/4/2005

Mocodo n'interdit pas la conversion en relationnel d'un tel MCD, mais celle-ci n'a aucun sens.

Si l'on veut garder les cardinalités sans les afficher, on peut les préfixer d'un -. Le résultat de la conversion en relationnel peut alors être interprété comme l'ensemble des lignes des différentes tables.

In [86]:
%%mocodo -t
ŒUVRE: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975
  
DF, -1N ŒUVRE, -_11 EXEMPLAIRE1
DF, -1N ŒUVRE, -_11 EXEMPLAIRE2
DF, -1N ŒUVRE, -_11 EXEMPLAIRE3

EXEMPLAIRE1: 1, bon état, 12/6/1975
EXEMPLAIRE2: 2, bon état, 1/8/1977
EXEMPLAIRE3: 3, reliure rongée, 3/4/2005
DF 1,1 DF 1,1 DF 1,1 ŒUVRE 612.NAT.34 J’apprends à lire à mes souris blanches mai 1975 EXEMPLAIRE 1 bon état 12/6/1975 EXEMPLAIRE 2 bon état 1/8/1977 EXEMPLAIRE 3 reliure rongée 3/4/2005
  • EXEMPLAIRE (_#612.NAT.34_, 1, bon état, 12/6/1975)
  • EXEMPLAIRE (_#612.NAT.34_, 2, bon état, 1/8/1977)
  • EXEMPLAIRE (_#612.NAT.34_, 3, reliure rongée, 3/4/2005)
  • ŒUVRE (612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975)

MCD interactif

Afficher des explications au survol

Les débutants ont souvent des doutes sur la sémantique de telle ou telle cardinalité. Cette information peut être incluse dans le texte-source en annotant les pattes correspondantes. Survolez les cardinalités du MCD ci-dessous pour faire apparaître leur description.

In [87]:
%%mocodo
Produit: réf. produit, libellé, prix unitaire
Inclure, 1N [Une commande inclut au moins un produit.] Commande, 0N [Un produit peut être commandé un nombre quelconque de fois.] Produit: quantité
Commande: num. commande, date, montant
DF, 0N [Un client peut passer zéro (prospect) ou plusieurs commandes.] Client, 11 [Une commande est passée par un et un seul client.] Commande
Client: réf. client, nom, adresse
Parrainer, 01 [Un client peut avoir été parrainé ou non.] Client, 0N [Un client peut parrainer d'autres clients.] Client : date parrainage
Inclure quantité 1,N 0,N DF 0,N 1,1 Parrainer date parrainage 0,1 0,N Produit réf. produit libellé prix unitaire Commande num. commande date montant Client réf. client nom adresse

Remarquez que la syntaxe est la même que pour les rôles, qui sont en plus utilisés lors du passage au relationnel. Comment Mocodo fait-il la différence ? En appliquant les règles suivantes :

  • si la note de patte commence par + ou -, c'est un rôle.
  • sinon, si elle ne contient aucun espace, c'est un rôle.
  • sinon, c'est une description de cardinalité.

Le même principe s'applique aux contraintes (survolez le Ⓘ) :

In [88]:
%%mocodo
Projet: num. projet, nom projet
:
Fournir, 1N Projet, 1N Pièce, 1N Société: quantité
Société: num. société, raison sociale

Requérir, 1N Projet, 0N Pièce: quantité
:
Pièce: réf. pièce, libellé pièce

(I) [Toute pièce fournie doit avoir été requise.] ..Pièce, ->Requérir, --Fournir, Projet
I Fournir quantité 1,N 1,N 1,N Requérir quantité 1,N 0,N Projet num. projet nom projet Société num. société raison sociale Pièce réf. pièce libellé pièce

Limitations.

  • Non pris en charge par les éditeurs de SVG comme Inkscape.
  • Ne semble pas fonctionner dans une page HTML statique (comme la version HTML de ce document sous GitHub).
  • Nécessite de faire confiance à un notebook (Trust notebook) pour s'afficher à la réouverture.

Dévoiler un MCD par étapes

Nouveauté de la version 3. Il est possible de faire apparaître progressivement les différentes « boîtes » constituant un MCD. Pour cela, il suffit d'indenter (décaler vers la droite à l'aide d'espaces ou de tabulations) au moins une ligne. Les éléments correspondants seront alors répartis sur autant de « calques » qu'il y a de niveaux d'indentations.

Voici par exemple un exercice consistant en la description du « réel perçu » d'une entreprise de VPC :

  1. Un produit est connu par une référence, un libellé et un prix unitaire.
  2. Toute commande inclut un produit ou plusieurs, chacun en une certaine quantité.
  3. Un client peut passer zéro (client potentiel) ou plusieurs commandes.
  4. Un client peut entrer dans la base par parrainage d'un autre client.

L'enseignant peut le présenter pas à pas en suivant les étapes de l'énoncé :

In [89]:
%%mocodo --colors ocean
      Parrainer, 01 Client, 0N Client : date parrainage
Produit: Réf. produit, Libellé, Prix unitaire
  Inclure, 1N Commande, 0N Produit: Quantité
 
    Client: Réf. client, Nom, Prénom, Adresse
    DF, 0N Client, 11 Commande
  Commande: Num. commande, Date, Montant
Parrainer date parrainage 0,1 0,N Inclure Quantité 1,N 0,N DF 0,N 1,1 Produit Réf. produit Libellé Prix unitaire Client Réf. client Nom Prénom Adresse Commande Num. commande Date Montant

Remarques.

  • Pas de règle sur la taille de l'indentation. Pour Mocodo, autant de niveaux d'indentation distincts, autant de calques.
  • Les différents calques sont codés directement dans le SVG. L'interaction ne nécessite donc aucun logiciel spécifique.
  • Sous Mocodo online, le MCD est toujours présenté entièrement dévoilé. Cela permet de voir directement le résultat d'une modification du texte-source.
  • Pour ajouter facilement de l'interactivité à un MCD existant :

    1. commencez par indenter au maximum toutes les lignes ;
    2. effacez l'indentation des lignes du premier calque ;
    3. décalez votre curseur de $n$ caractères vers la droite ;
    4. placez-vous tour à tour sur les lignes à intégrer au deuxième calque et effacez les espaces surnuméraires ;
    5. recommencez à l'étape 3 jusqu'au dernier calque.

    Depuis la version 4.0, l'éditeur de Mocodo online vous permet de créer des curseurs multiples, ce qui simplifie encore ces opérations.

Limitations.

  • Pas de granularité plus fine que la ligne (entité ou association avec toutes ses pattes et cardinalités).
  • Pas de prise en charge des touches directionnelles. Cela serait sans doute possible, mais difficilement compatible avec la présence de plusieurs MCD interactifs sur une même page (comme dans cette documentation).

Éviter qu'une interaction sur un SVG ne s'applique à un autre.

Dans le cas très rare où plusieurs SVG interactifs générés à partir du même texte-source coexistent sur une même page web, une interaction opérée sur l'un s'applique également à tous les autres. Par exemple, cliquer sur l'un des ronds gris de l'une des figures ci-dessous agira sur les deux figures :

In [90]:
%%mocodo
FOO: foo
  BAR: bar
FOO foo BAR bar
In [91]:
%%mocodo
FOO: foo
  BAR: bar
FOO foo BAR bar

Ce problème trahit une « collision » : différents éléments du DOM se sont vus attribuer la même empreinte (obtenue par hachage du texte-source). La solution est de passer un entier discriminant qui, par concaténation, fera de ces empreintes de véritables identifiants.

In [92]:
%%mocodo --uid_suffix 1
FOO: foo
  BAR: bar
FOO foo BAR bar
In [93]:
%%mocodo --uid_suffix 2
FOO: foo
  BAR: bar
FOO foo BAR bar

Explications du passage au relationnel

Les gabarits de conversion en MLD (à savoir html, markdown, latex et text) admettent une sous-sous-option e qui accompagne le résultat par des explications détaillées du mécanisme de passage :

In [94]:
%mocodo -i ccp -t markdown:e

ccp_mld.md
  • Client (Réf. client, Nom, Prénom, Adresse)

    • Le champ Réf. client constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Client.
    • Les champs Nom, Prénom et Adresse étaient déjà de simples attributs de l'entité Client.
  • Commande (Num. commande, Date, Montant, #Réf. client)

    • Le champ Num. commande constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Commande.
    • Les champs Date et Montant étaient déjà de simples attributs de l'entité Commande.
    • Le champ Réf. client est une clé étrangère. Il a migré par l'association de dépendance fonctionnelle Passer à partir de l'entité Client en perdant son caractère identifiant.
  • Inclure (_#Num. commande_, _#Réf. produit_, Quantité)

    • Le champ Num. commande fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Commande.
    • Le champ Réf. produit fait partie de la clé primaire de la table. C'est une clé étrangère qui a migré directement à partir de l'entité Produit.
    • Le champ Quantité était déjà un simple attribut de l'association Inclure.
  • Produit (Réf. produit, Libellé, Prix unitaire)

    • Le champ Réf. produit constitue la clé primaire de la table. C'était déjà un identifiant de l'entité Produit.
    • Les champs Libellé et Prix unitaire étaient déjà de simples attributs de l'entité Produit.

Nous avons essayé d'être aussi précis que possible, tout en « factorisant » avec soin les lignes consécutives suseptibles de l'être. Vous pouvez adapter ces explications à votre enseignement en modifiant une copie du gabarit html-ce.yaml, dont les autres sont dérivés.

MCD à compléter

Les MCD à trous sont des exercices classiques d'introduction aux bases de données.

Supprimer le marquage d'un identifiant

Pour éviter le marquage automatique du premier attribut d'une entité comme identifiant, il suffit de le préfixer par un tiret bas (_) : ce caractère est donc un commutateur, qui souligne un attribut non souligné par défaut, et désouligne un attribut souligné par défaut.

In [95]:
%%mocodo
CLIENT: _Réf. client, Nom, Prénom, Adresse
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: _Num. commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PRODUIT: _Réf. produit, Libellé, Prix unitaire
PASSER 0,N 1,1 INCLURE Quantité 1,N 0,N CLIENT Réf. client Nom Prénom Adresse COMMANDE Num. commande Date Montant PRODUIT Réf. produit Libellé Prix unitaire

Masquer un couple de cardinalités

Vous pouvez masquer n'importe quelles cardinalités en les remplaçant par XX ou en les préfixant d'un - :

In [96]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, XX CLIENT, XX COMMANDE
COMMANDE: Num. commande, Date, Montant
INCLURE, -1N COMMANDE, -0N PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
PASSER INCLURE Quantité CLIENT Réf. client Nom Prénom Adresse COMMANDE Num. commande Date Montant PRODUIT Réf. produit Libellé Prix unitaire

Nouveauté de la version 4.0. Si la cardinalité comporte un et un seul X, l'autre caractère sera affiché tout seul.

Masquer un attribut

Vous pouvez mettre deux virgules consécutives pour réserver la place d'un attribut manquant. Les espaces insécables sont préservés, ce qui permet de réserver plus d'espace horizontal, cf. ci-dessous premier attribut vide de INCLURE.

In [97]:
%%mocodo
CLIENT: Réf. client,,, 
PASSER, XX CLIENT, XX COMMANDE
COMMANDE: , Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité,,,,
PRODUIT: Réf. produit, Libellé, Prix unitaire
PASSER INCLURE Quantité 1,N 0,N CLIENT Réf. client COMMANDE Date Montant PRODUIT Réf. produit Libellé Prix unitaire

Régression de la version 4.0. Les espaces insécables ne sont plus préservés. Il n'y a donc plus d'autre moyen de réserver davantage d'espace horizontal que d'employer le style blank (paragraphe suivant).

Ne faire apparaître que le squelette du schéma conceptuel

Vous pouvez transformer en exercice à trous n'importe quel MCD en rendant complètement transparentes les couleurs des attributs, associations et cardinalités. Le style blank a été prédéfini à cet effet:

In [98]:
%mocodo -i ccp --colors=blank
Passer 0,N 1,1 Inclure Quantité 1,N 0,N Client Réf. client Nom Prénom Adresse Commande Num. commande Date Montant Produit Réf. produit Libellé Prix unitaire

Attention, n'utilisez cette méthode que pour la projection : l'information textuelle est toujours présente, susceptible d'être sélectionnée et collée ailleurs. Vous pouvez bien sûr empêcher cette possibilité en convertissant le SVG en PNG, mais le plus simple est d'appliquer une réécriture empty :

In [99]:
%mocodo -i ccp -t empty # équivalent de "delete:types,notes,attrs,cards"
Passer Inclure Client Commande Produit

ccp.mcd
%%mocodo 
Client:  ,  ,  ,  
Passer, XX Client, XX Commande
Commande:  ,  ,  
Inclure, XX Commande, XX Produit:  
Produit:  ,  ,

Obfuscation d'un MCD donné

Obfusquer un MCD consiste à vider celui-ci de sa sémantique de surface en substituant des chaînes aléatoires à tous les libellés. Cela permet de créer des exemples d'illustration de telle ou telle notion « pure » sans risquer de voir son public se focaliser sur des détails-métier (c'est l'équivalent de la variable méta-syntaxique foobar dans le contexte de la pédagogie de la programmation).

In [100]:
%mocodo -i ccp --seed=1 --select mcd -t obfuscate  # raccourci pour "obfuscate:labels"
Libellum 0,N 1,1 Mulieres Carus 1,N 0,N Scriptam Spicula Persequitur Defensor Frontem Fuit Artes Leporis Sociis Theatro Reperiri Serpentes Amissum

En argument, vous pouvez ajouter le chemin d'un fichier texte quelconque où puiser les mots de substitution. Par exemple, le texte du README de ce projet :

In [101]:
%mocodo -i ccp -t obfuscate:labels=../../README.md --seed=1 --select mcd
Épargner 0,N 1,1 Magique Différente 1,N 0,N Local Transparente Étudiants Copie Installer Invoque Labels Weak Ligne Une Insertion Ainsi Spécialisation

Mocodo essaie d'abord de trouver ce fichier à l'endroit indiqué. En cas d'échec, il le cherche (avec extension .txt facultative) parmi ceux distribués avec le logiciel, à savoir:

  • "lorem.txt" (6464 mots) : le faux-texte le plus courant, augmenté d'une sélection des 10000 mots latins les plus courants compilés par Kyle P. Johnson, le tout privé de ses doublons et des mots de moins de 3 lettres ("lorem_ipsum.txt" avant la version 4.0).
  • "fr.txt" (3396 mots) : une liste des 4000 mots français les plus courants, privée de ceux comportant une apostrophe ou moins de 4 lettres. Source : http://wortschatz.uni-leipzig.de/index.html via Wikitionary. Nouveauté de la version 4.0.
  • "fr5.txt" (464 mots): la liste de "fr.txt", restreinte aux mots de 5 lettres. Nouveauté de la version 4.0.
  • "en4.txt" (640 mots): une sélection (SFW) de mots anglais de quatre lettres ("four_letter_words.txt" avant la version 4.0).
  • "disparition.txt" (7489 mots) : le lexique du célèbre roman lipogrammatique de Georges Perec, privé des mots de moins de 4 lettres.

En cas de nouvel échec, il se rabat sur "lorem.txt".

NB. L'algorithme s'assure que la distance de Damerau-Levenshtein entre deux libellés de substitution quelconques est d'au moins 3. En clair, cela signifie que, si vous donnez en examen un exercice de conversion en relationnel basé sur un tel MCD, les erreurs de transcription d'un étudiant stressé, inattentif, illettré, dyslexique, roublard, ou tout cela à la fois, ne devraient pas vous empêcher de lui octroyer les points qui lui reviennent.

Croissance stochastique

Vous pouvez créer un MCD partiellement aléatoire à partir d'un MCD donné en lui ajoutant un nombre n d'associations (avec les entités nécessaires) :

In [102]:
%mocodo -i ccp -t grow:n=4 arrange --seed=1 --select mcd
Ternaire 9 0,N 1,1 1,N Ternaire 7 1,1 0,N 0,N Passer 0,N 1,1 Inclure Quantité 1,N 0,N Réflexive 11 at 11 1 1,N 1,1 Réflexive 10 at 10 1 1,1 0,1 Entité 8 id 8 1 at 8 2 Entité 6 id 6 1 at 6 2 at 6 3 Commande Num. commande Date Montant Client Réf. client Nom Prénom Adresse Produit Réf. produit Libellé Prix unitaire
  • Des sous-options pré-définies (données ci-dessous avec leur valeur par défaut après le =) permettent de spécifier finement le nombre désiré :

    • d'associations réflexives (arity_1=2) ;
    • d'associations ternaires (arity_3=2) ;
    • d'associations quaternaires (arity_4=0) ;
    • d'associations doubles, i.e., associant le même couple d'entités (doubles=1) ;
    • d'identifiants composites (composites=1) ;
    • d'attributs maximum par entité (ent_attrs=4) ;
    • d'attributs maximum par association (assoc_attrs=2).
  • On ne peut pas préciser directement le nombre d'associations binaires : si le nombre total des autres associations spécifiées n'arrivent pas à n, elles viennent en complément.

  • Des sous-options de forme plus ou moins libre décrivent les cardinalités. Par exemple, _11-*N=2 créera deux entités faibles et /*N-*N un agrégat. Les associations de complément sont *N-*N.

Avec la sous-option from_scratch, le MCD de départ est vide. À titre d'exemple, voici la transformation complexe invoquée par Mocodo online pour créer un MCD d'entraînement à la conversion au relationnel, accompagné de cette dernière. Notez la création de rôles par défaut : ils permettent de simuler le rétablissement de la sémantique des associations disparues.

In [103]:
%mocodo --seed=2 --mld -t grow:from_scratch,arity_3=1,_11-*N=1 obfuscate create:roles lower:roles arrange
Serum putabant 1,N 0,N 0,1 Iurandum 1,1 0,1 Absit 1,N 1,N Aetatem 1,N 0,N Ceciderunt 1,N 1,1 Tenebant 1,N 1,N Ademptum 0,N 0,N Postremum 1,N 0,N Rupit miraculo 1,N 1,1 Virilem 1,1 1,N Discipulus vendidit integris alexandro Occisus magnus ennius capuam quaestiones Crudelitatem faciendam menses Periculosum insidiis amplexus paret Crebra cornua dimidio mario caecus Pisces ageretur status societatem Vellent tura gracchus Spiritus interdum vasa Quoniam sardiniam claudio infestus
  • Absit (_#faciendam_, _#insidiis_)
  • Ademptum (_#cornua 1_, _#cornua 2_)
  • Aetatem (_#cornua_, _#insidiis_)
  • Crebra (cornua, dimidio, mario, caecus, #cornua ceciderunt)
  • Crudelitatem (faciendam, menses)
  • Discipulus (vendidit, integris, alexandro)
  • Occisus (magnus, ennius, capuam, quaestiones, #vendidit serum, #insidiis serum, putabant, #cornua iurandum)
  • Periculosum (insidiis, amplexus, paret)
  • Pisces (ageretur, status, societatem)
  • Postremum (_#sardiniam_, _#ageretur_)
  • Quoniam (sardiniam, claudio, infestus)
  • Tenebant (_#insidiis_, _#interdum_, _#vasa_, _#tura_)
  • Vellent (interdum rupit, vasa rupit, tura, gracchus, miraculo, #sardiniam virilem)

Il n'est pas impossible que le MCD résultant soit incorrect (p. ex., apparition d'une identification relative circulaire), mais les contrôles effectués a priori et a posteriori devraient dans la majorité des cas produire quelque chose de raisonnable.

Génération d'un QR code

Impressionnez votre public en accompagnant l'option -t share de --defer :

In [104]:
%mocodo -i ccp -t share --defer

ccp_url.svg