In [ ]:
%reload_ext mocodo_magic
Mocodo est un logiciel d'aide à l'enseignement et à la conception des bases de données relationnelles.
Ci-dessous, un exemple d'appel du programme (première ligne) sur un texte d'entrée (lignes suivantes), puis, en sortie, le MCD et le MLD correspondants:
In [ ]:
%%mocodo --mld --colors ocean --shapes copperplate --relations diagram markdown_data_dict
DF, 11 Élève, 1N Classe
Classe: Num. classe, Num. salle
Faire Cours, 1N Classe, 1N Prof: Vol. horaire
Catégorie: Code catégorie, Nom catégorie
Élève: Num. élève, Nom élève
Noter, 1N Élève, 0N Prof, 0N Matière, 1N Date: Note
Prof: Num. prof, Nom prof
Relever, 0N Catégorie, 11 Prof
Date: Date
Matière: Libellé matière
Enseigner, 11 Prof, 1N Matière
L'appel ci-dessus a également construit le dictionnaire des données:
In [ ]:
# %load mocodo_notebook/sandbox_data_dict.md
Ainsi que le diagramme relationnel, qui peut être visualisé par un nouvel appel:
In [ ]:
%mocodo --input mocodo_notebook/sandbox.mld --colors desert
La devise de Mocodo, « nickel, ni souris », en résume les principaux points forts:
Mocodo est libre, gratuit et multiplateforme. Si vous l'aimez, répandez la bonne nouvelle en incluant l'un de ses logos dans votre support: cela multipliera ses chances d'attirer des contributeurs qui le feront évoluer.
Tapez ensuite sous un terminal la ligne de commande:
pip install mocodo_magic
Cette commande installera Mocodo, ainsi que l'extension IPython qui permettra de l'utiliser dans un document comme celui-ci (il s'agit d'un Jupyter notebook).
Toujours sous un terminal, tapez:
mocodo
Si votre système se plaint que cette commande n'existe pas, localisez le fichier mocodo
et ajoutez le chemin du répertoire contenant à votre PATH
:
Pour mettre la « commande magique » mocodo
à disposition d'un notebook donné, évaluez dans celui-ci la cellule suivante:
%reload_ext mocodo_magic
Techniquement, %load_ext mocodo_magic
suffit, mais cette forme vous épargnera un message d'erreur si vous réévaluez ultérieurement la cellule. Pour tester, évaluez une cellule avec:
In [ ]:
%%mocodo
MISSION: accomplie
Pour charger automatiquement mocodo_magic
à chaque ouverture d'un notebook (ce qui dispense d'évaluer %load_ext mocodo_magic
) :
exécuter sous un terminal :
ipython profile create
éditer le fichier créé (p. ex.: ~/.ipython/profile_default/ipython_config.py
) pour remplacer les lignes suivantes :
## A list of dotted module names of IPython extensions to load.
#c.InteractiveShellApp.extensions = []
par celles-ci :
## A list of dotted module names of IPython extensions to load.
c.InteractiveShellApp.extensions = [
"mocodo_magic",
]
Une fois Python installé, tapez sous un terminal:
pip install mocodo
Vous ne bénéficierez pas de Jupyter Notebook, mais vous pourrez utiliser Mocodo en ligne de commande.
Vous pouvez utiliser Mocodo:
Faites pointer votre navigateur sur http://mocodo.net: vous pouvez commencer à taper votre MCD. Appuyez à tout moment sur le bouton de génération pour visualiser le diagramme conceptuel et en déduire les relations. Une fois que 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 désiré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, vous pouvez installer Mocodo sur votre machine.
Tout a été fait pour faciliter au maximum la prise en main. Ainsi, pour peu que vous sachiez lancer une console (cmd
sous Windows, Terminal sous Mac OS X), il vous suffit d'y entrer:
mocodo
Invoqué sous cette forme, le script 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 selon vos besoins avant de lancer la commande.
La commande mocodo
admet de nombreux arguments optionnels. Voici la traduction en français de la liste affichée par l'argument --help
. Destinée à servir de référence, elle peut être sautée sans inconvénient à la première lecture. Nous avons ajouté des liens vers des exemples d'utilisation dans ce document; notez cependant que les %%
ou %
qui préfixent la « commande magique » mocodo
doivent être omis de la ligne de commande.
--help
.--version
.--language CODE
.fr
, en
, ...) (défaut: langue du système).--restore
.sandbox.mcd
et params.json
dans le répertoire d'entrée, puis termine (défaut: False
).--params_path PATH
.params.json
dans le répertoire d'entrée. Si ce fichier n'existe pas, utilise les paramètres par défaut (défaut: params.json
).--input PATH
.sandbox.mcd
). --output_dir PATH
.--encodings [STR [STR ...]]
.utf8
, puis encodage historique de la plateforme).--extract
.False
).--image_format {svg,nodebox}
.--print_params
.False
).--df STR
.DF
).--card_format STR
.{min_card},{max_card}
).--strengthen_card STR
._1,1_
).--flex FLOAT
.0.75
).--tkinter
.False
).--colors PATH
.colors
, ou chemin vers un fichier personnel (défaut: bw
).--shapes PATH
.shapes
, ou chemin vers un fichier personnel (défaut: dépendant de votre système).--scale SCALE
.1.0
).--hide_annotations
.False
).--relations [NAME [NAME ...]]
.relation_templates
(défaut: html text
).--disambiguation {numbers_only,annotations}
.annotations
).--title STR
.Sans titre
).--guess_title
.False
).--arrange [{bb,ga,lp}]
.None
).--timeout SECONDS
.None
).--verbose
.False
).--flip {h,v,d}
.None
).--fit [INT]
.None
).--obfuscate [PATH]
.lorem
(défaut: None
).--obfuscation_max_length INT
.None
).--obfuscation_min_distance INT
.--seed FLOAT
.None
).Sous-options accessibles avec l'option --arrange=bb
.
--call_limit INT
.10000
).--min_objective INT
.0
).--max_objective INT
.15
).--organic
.False
).Sous-options accessibles avec l'option --arrange=ga
.
--population_size INT
.1000
).--crossover_rate RATE
.0.9
).--mutation_rate RATE
.0.06
).--sample_size INT
.7
).--max_generations INT
.300
).--plateau INT
.30
).Sous-options accessibles avec l'option --arrange=lp
.
--engine [{cplex,gurobi}]
.None
).Ignorées lors de l'appel en ligne de commande.
Pour éviter d'avoir à invoquer Mocodo répétitivement avec une longue kyrielle d'options, vous pouvez mettre celles-ci une fois pour toutes dans un fichier params.json
situé dans le répertoire courant. La commande:
mocodo --restore
... le fait pour vous avec un fichier de paramètres vide, i.e. , un fichier-texte réduit aux deux caractères {}
(attention, elle rétablit aussi le fichier sandbox.mcd
à son contenu par défaut). Vous êtes encouragés à modifier ce fichier de paramètres selon vos goûts et vos besoins. De la sorte, le style de vos MCD pourra être maintenu à moindre frais à travers tous vos documents. En cas de besoin, vous pourrez toujours ponctuellement passer outre ces réglages en en précisant d'autres en ligne de commande. Plus précisément, chaque paramètre est déterminé:
--params_path
;params.json
du répertoire courant;Si vous lancez Mocodo avec l'option --print_params
, la valeur courante de l'ensemble des paramètres sera affichée. Vous pouvez envoyer la sortie dans un fichier params.json
et la modifier à votre gré pour une prise en compte lors du lancement suivant.
Elle nécessite l'installation de l'extension notebook mocodo
, laquelle doit en outre être rechargée à chaque ouverture (cf. première cellule de ce document). On a ainsi déclaré une « commande magique » mocodo
qui sera invoquée en la préfixant:
%%
pour prendre toutes les lignes suivantes de la cellule comme texte d'entrée du MCD;%
si l'on récupère l'entrée ailleurs (avec --input
), ou qu'on n'en a pas besoin (p. ex., --help
ou --print_params
).À part ça, la syntaxe est généralement la même qu'en ligne de commande, ce qui devrait faciliter le passage de l'un à l'autre.
Il peut être utile de comprendre ce qui se passe en coulisses lorsque l'on invoque la commande magique sur une cellule:
mocodo_notebook
;sandbox.mcd
;sandbox.svg
, sandbox.html
, etc.;--no_mcd
); avec l'option --mld
, le schéma relationnel est également affiché au-dessous (au format HTML);--arrange
, --flip
, --obfuscate
, ...), Mocodo est automatiquement relancé sur celle-ci, permettant de visualiser le diagramme et/ou le schéma relationnel correspondants.Tous les fichiers peuvent être lus dans le répertoire mocodo_notebook
(commande magique %load
, mise en commentaire dans ce notebook pour éviter de recharger le fichier à chaque exécution).
Les trois exemples de l'introduction illustrent plusieurs de ces techniques usuelles:
%%mocodo --mld --colors ocean --shapes copperplate --relations diagram markdown_data_dict
... invoque le programme en demandant l'affichage du diagramme conceptuel (implicitement), du schéma relationnel (avec --mld
), des changements de style (avec --colors
et --shapes
) et la production d'un diagramme relationnel (--relations diagram
) et d'un dictionnaire de données (markdown_data_dict
). Le contenu de celui-ci est rechargé et visualisé à l'aide de la commande suivante:
%load mocodo_notebook/sandbox_data_dict.md
Tandis que le diagramme relationnel (MLD) est tracé en relançant Mocodo dessus:
%mocodo --input mocodo_notebook/sandbox.mld --colors desert
Nouveauté de la version 2.0.20 (contribution de Thomas Giro). Avec les options --arrange
, --flip
et --obfuscate
le résultat de l'évaluation de la cellule est un nouveau MCD, normalement affiché au-dessous. Ajoutez l'option --replace
pour substituer ce MCD au contenu de la cellule. Réévaluez alors celle-ci pour tracer le MCD résultant, ou annulez la dernière opération pour revenir au contenu originel.
Par exemple, l'évaluation de la cellule suivante:
In [ ]:
%%mocodo --flip=v --replace
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
... remplacerait celle-ci par celle-là:
In [ ]:
%%mocodo
PRODUIT: Réf. produit, Libellé, Prix unitaire
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
COMMANDE: Num commande, Date, Montant
PASSER, 0N CLIENT, 11 COMMANDE
CLIENT: Réf. client, Nom, Prénom, Adresse
Si vous voulez éviter de préciser à chaque fois les mêmes arguments (par exemple un changement de couleurs), vous pouvez placer un fichier params.json
dans le répertoire mocodo_notebook
. Mocodo peut même vous aider à le faire en exécutant la cellule suivante:
In [ ]:
%mocodo --print_params
Son évaluation remplace son propre contenu par des lignes de code similaires à:
In [ ]:
# You may edit and run the following lines
import codecs, json
params = u"""
{
"arrange": null,
"call_limit": 10000,
"colors": "bw",
"crossover_rate": 0.9,
"df": "DF",
"disambiguation": "annotations",
"encodings": [
"utf8",
"macroman"
],
"extract": false,
"flip": null,
"guess_title": false,
"hide_annotations": false,
"image_format": "svg",
"input": "mocodo_notebook/sandbox.mcd",
"language": "fr",
"max_generations": 300,
"max_objective": 15,
"min_objective": 0,
"mld": false,
"mutation_rate": 0.06,
"no_mcd": false,
"obfuscate": null,
"obfuscation_max_length": null,
"organic": false,
"output_dir": "mocodo_notebook",
"plateau": 30,
"population_size": 1000,
"print_params": false,
"relations": [
"html",
"text"
],
"replace": false,
"restore": false,
"sample_size": 7,
"scale": 1.0,
"seed": null,
"sep": ",",
"shapes": "copperplate",
"timeout": null,
"title": "Sans titre",
"tkinter": false,
"verbose": false
}
"""
try:
json.loads(params)
except:
raise RuntimeError("Invalid JSON. Find out why on http://jsonlint.com")
with codecs.open("mocodo_notebook/params.json", "w", "utf8") as f:
f.write(params.strip())
Modifiez la variable params
à votre gré en respectant la syntaxe JSON (attention en particulier au dernier couple clef-valeur, qui n'est pas terminé par une virgule). Exécutez la cellule pour créer un fichier de nom et emplacement adéquats (notez que la valeur de --print_params
a été passée à false
pour vous éviter de le faire à la main).
In [ ]:
%%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
La syntaxe ne devrait pas poser problème:
À noter :
%%mocodo
... ne fait pas partie de la description. Dans ce document, elle permet de faire appel à une « commande magique », qui lance Mocodo sur les lignes qui la suivent. Sauf sous Jupyter Notebook, vous pouvez l'omettre dans votre texte d'entrée.%
) sont ignorées. Cela permet de placer en en-tête un commentaire qui pourra être préservé lors des éventuels réarrangements ultérieurs.utf8
, il se rabattra sur le codec d'Europe de l'Ouest associé historiquement à votre plateforme: iso-8859-15
pour Windows et Linux, mac-roman
pour Mac OS X. Si les accents n'apparaissent pas correctement, vous aurez encore trois solutions:--encodings
;params.json
la liste des encodages pris en charge.
In [ ]:
%%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
Si on a plusieurs dépendances fonctionnelles à représenter, on devra suffixer le DF par un numéro (cf. cet exemple).
In [ ]:
%%mocodo
HOMME: Num. SS, Nom, Prénom
ENGENDRER, 0N HOMME, 11 HOMME
L'ordre et la séparation des lignes de la description permet de spécifier à coût zéro un plongement grossier, mais qui s'avère en général suffisant:
In [ ]:
%%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
Les boîtes sont placées aux intersections d'une grille invisible assurant que leurs centres soient alignés aussi bien horizontalement que verticalement. C'est ce qui en général est le plus satisfaisant esthétiquement, mais d'autres retouches peuvent être opérées manuellement dans le fichier de sortie.
Le plongement fait l'objet d'une « compression » horizontale et verticale. Par exemple, ci-dessus, il y a un espace horizontal négatif entre le bord droit de l'entité de gauche et le bord gauche de l'entité de droite.
Préfixer d'un caractère de soulignement (_
) le(s) second, troisième, etc. attributs pour les ajouter à l'identifiant.
In [ ]:
%%mocodo
GRATTE-CIEL: latitude, _longitude, nom, hauteur, année de construction
Préfixer d'un caractère de soulignement (_
) une cardinalité (1,1) pour indiquer que l'entité distinguée est faible. Dans le diagramme, les identifiants (ou discriminants) d'une telle entité seront soulignés en pointillés, tandis que le (1,1) sera souligné d'un trait plein.
In [ ]:
%%mocodo
ŒUVRE: Cote œuvre, Titre, Date parution
DF, 1N ŒUVRE, _11 EXEMPLAIRE
EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat
Nouveauté de la version 2.1. Traditionnellement, l'identification relative est dénotée par des parenthèses autour des cardinalités. Cette notation (ou toute autre) peut maintenant être obtenue avec l'option --strenghten_card
:
In [ ]:
%%mocodo --strengthen_card (1,1)
ŒUVRE: Cote œuvre, Titre, Date parution
DF, 1N ŒUVRE, _11 EXEMPLAIRE
EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat
Une association ne peut renforcer plus d'une entité faible. Ainsi, une erreur se produit si l'on remplace le 1N
par _11
:
In [ ]:
%%mocodo
ŒUVRE: Cote œuvre, Titre, Date parution
DF, _11 ŒUVRE, _11 EXEMPLAIRE
EXEMPLAIRE: Num. exemplaire, État du livre, Date d'achat
Suffixer 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 [ ]:
%%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
La position de la flèche sur la patte peut être réglée individuellement dans la table d'association ratio
du script Python généré (par défaut, sandbox_svg.py
ou sandbox_nodebox.py
) ou sous l'onglet Retouches de la version en ligne. La valeur correspondante peut varier de 0.0
(flèche cachée sous la boîte d'origine) à 1.0
(par défaut, pointe de la flèche au contact du bord de la boîte de destination, compte non tenu de l'arrondi s'il s'agit d'une association).
Plusieurs styles prédéfinis sont distribués avec l'application. Un style se définit comme la combinaison d'une palette de couleurs (répertoire colors
) avec un dictionnaire de polices et de dimensions (répertoire shapes
). Une changement d'échelle d'un facteur multiplicatif positif peut être précisé avec l'argument --scale
.
Vous pouvez bien sûr créer vos propres styles en vous inspirant des fichiers fournis. Si vous êtes particulièrement content d'un style, soumettez-le pour inclusion dans une prochaine distribution.
Chaque attribut peut être assorti d'annotations entre crochets. Ignorées au niveau du tracé du MCD, elles sont interprétées comme des types de données lors de la génération d'un code-source SQL.
Par défaut, les cardinalités sont séparées par une virgule.
Nouveauté de la version 2.1. On peut maintenant opter pour un format quelconque:
In [ ]:
%%mocodo --card_format={min_card}/{max_card}
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
Certaines fautes de frappe fréquentes (inversion des cardinalités minimale et maximale, lettre « O » au lieu du chiffre « 0 ») sont silencieusement rectifiées:
formes erronées | forme rectifiée |
---|---|
O1 , o1 , 10 , 1O , 1o |
01 |
ON , oN , NO , No , N0 |
0N |
On , on , no , nO , n0 |
0n |
N1 |
1N |
n1 |
1n |
Les cardinalités (N,N), qui selon une certaine école dénotent une cardinalité minimale supérieure à 1, sont laissées telles quelles.
In [ ]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, oN CLIENT, 11 COMMANDE
COMMANDE: Num commande, Date, Montant
INCLURE, lN COMMANDE, ON PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
Il est possible d'activer l'encerclement d'un autre sigle que DF. C'est ce sigle qui devra alors apparaître en entrée, par exemple:
In [ ]:
%%mocodo --df=CIF
CLIENT: Réf. client, Nom, Prénom, Adresse
CIF, 0N CLIENT, 11 COMMANDE
COMMANDE: Num commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
Comme le cercle est alors un peu plus grand, on peut vouloir régler (a priori une fois pour toutes) le ratio défini dans le dictionnaire de shapes
:
"df_text_height_ratio" : 1.00,
Normalement on doit choisir des noms différents pour toutes les boîtes (entités et associations) du MCD, à l'exception des associations de dépendance fonctionnelle figurées par un sigle. On a vu que dans ce cas, il suffisait d'ajouter à leur nom un suffixe numérique: celui-ci n'apparaîtra pas en sortie. Cette possibilité vaut pour n'importe quelle boîte.
Elle servira typiquement à « distribuer » une entité DATE réduite à son identifiant date, mais associée à de nombreuses entités qui n'ont rien à voir entre elles. Sachant qu'une telle entité est amenée à disparaître lors du passage au relationnel, il n'y a aucun inconvénient à en créer plusieurs, et cela peut avoir l'avantage de faciliter (ou même de rendre possible) l'obtention d'une bonne mise en page.
Par exemple, la mise en page du MCD suivant est indûment complexifiée par le haut degré de l'entité DATE.
In [ ]:
%%mocodo
:
Rhoncus: dolor a, bibendum, euismod, consectetuer, leo
Porttitor, 1N Rhoncus, 1N Curabitur
:
:
Ultricies, 11 Rhoncus, 0N Egestas
Imperdiet, 0N Egestas, 0N Curabitur, 0N DATE
Curabitur: blandit, suscipit
Mollis, 0N Curabitur, 0N Curabitur
:
:
Egestas: vivamus, semper, aliquam
Pharetra, 0N Curabitur, 0N DATE, 0N Vitae justo: massa
Vitae justo: lobortis, purus
adipiscing, 0N Curabitur, 0N Vitae justo, 0N DATE
:
:
DATE: date
:
:
Ajouter une autre entité DATE (sous le nom de DATE2) permettra à Mocodo de calculer une mise en page à la fois plus agréable à l'œil et plus compacte ($4\times3$ au lieu de $5\times4$). La sémantique est inchangée.
In [ ]:
%%mocodo
Egestas: vivamus, semper, aliquam
DATE: date
Pharetra, 0N Curabitur, 0N DATE, 0N Vitae justo: massa
Vitae justo: lobortis, purus
Ultricies, 11 Rhoncus, 0N Egestas
Imperdiet, 0N Egestas, 0N Curabitur, 0N DATE
Curabitur: blandit, suscipit
adipiscing, 0N Curabitur, 0N Vitae justo, 0N DATE2
Rhoncus: dolor a, bibendum, euismod, consectetuer, leo
Porttitor, 1N Rhoncus, 1N Curabitur
Mollis, 0N Curabitur, 0N Curabitur
DATE2: date
Si vous n'êtes pas enseignant de bases de données, vous pouvez passer directement à la section suivante.
La technique de duplication que l'on vient de voir 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 [ ]:
%%mocodo
ŒUVRE1: cote, titre, date de publication
::::
ŒUVRE2: 612.NAT.34, J'apprends à lire à mes souris blanches, mai 1975
:
DF1, 1N ŒUVRE1, _11 EXEMPLAIRE1
:::
DF2, XX ŒUVRE2, XX EXEMPLAIRE2
DF3, XX ŒUVRE2, XX EXEMPLAIRE3
DF4, 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
Les débutants ont souvent des doutes sur la sémantique de telle ou telle cardinalité. Cette information peut désormais être incluse dans le texte-source, en annotant les pattes correspondantes, pour apparaître à la demande lors du rendu (utile pour créer des exercices à faire en TD ou en autonomie).
Survolez les cardinalités du MCD ci-dessous pour faire apparaître leur description.
In [ ]:
%%mocodo
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, 0N [Un client peut passer un nombre quelconque de commandes.] CLIENT, 11 [Toute commande est passée par un en un seul client.] COMMANDE
COMMANDE: Num commande, Date, Montant
INCLURE, 1N [Une commande peut inclure plusieurs produits distincts, et en inclut au moins un.] COMMANDE, 0N [Certains produits ne sont jamais commandés, d'autres le sont plusieurs fois.] PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
Les annotations s'insèrent entre cardinalités et nom de l'entité. Elles sont délimitées par des crochets droits.
Avec l'option --disambiguation=annotations
(par défaut), elles sont également exploitables lors du passage au relationnel pour préciser la sémantique d'une clef étrangère.
L'affichage est désactivé avec l'option --hide_annotations
.
Limitations.
--image_format=nodebox
.Les MCD à trous sont des exercices classiques d'introduction aux bases de données.
Pour éviter le marquage automatique du premier attribut d'une entité comme identifiant, il suffit de le préfixer par un _
(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 [ ]:
%%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
Vous pouvez masquer n'importe quelles cardinalités en les remplaçant pas XX
(ci-dessous à gauche) :
In [ ]:
%%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
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 [ ]:
%%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
Enfin, 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 [ ]:
%%mocodo --colors=blank
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
Attention, n'utilisez pas cette méthode si vous souhaitez diffuser l'exercice sous forme électronique: l'information textuelle est toujours présente, susceptible d'être sélectionnée et collée ailleurs pour être lue. Vous pouvez bien sûr empêcher cette possibilité en convertissant la figure dans un format bitmap (comme PNG ou GIF); mais le plus simple est de combiner les deux méthodes précédentes:
In [ ]:
%%mocodo
CLIENT: , ,,
PASSER, XX CLIENT, XX COMMANDE
COMMANDE: , ,
INCLURE, XX COMMANDE, XX PRODUIT:
PRODUIT: , ,
L'obfuscation d'un MCD consiste à vider celui-ci de sa sémantique de surface, en substituant à tous les libellés des chaînes aléatoires. Le résultat sera par exemple utilisé pour montrer que les principales règles de passage du schéma conceptuel au schéma relationnel peuvent être appliquées « bêtement », c'est-à-dire sans comprendre le fonctionnement de l'organisme modélisé.
Ainsi, dans l'exemple ci-dessous, les libellés du MCD CLIENT-COMMANDE-PRODUIT sont remplacés par des mots tirés au hasard:
In [ ]:
%%mocodo --obfuscate
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
Nouveauté de la version 2.0.20. Pour remplacer le texte de la cellule par le résultat de son évaluation, ajoutez l'option --replace
.
En argument, vous pouvez ajouter le chemin d'un fichier texte UTF-8 quelconque où puiser les mots de substitution. Par exemple, le texte même de cette documentation:
In [ ]:
%%mocodo --obfuscate=fr_refman.ipynb --obfuscation_max_length=10 --seed=5 --no_mcd
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
Mocodo essaie d'abord de trouver ce fichier à l'endroit indiqué. En cas d'échec, il le cherche (avec extension .txt
facultative) parmi les textes distribués avec le logiciel, à savoir:
"lorem_ipsum.txt"
: le faux-texte le plus courant."disparition.txt"
: le lexique du célèbre roman lipogrammatique de Georges Perec."four_letter_words.txt"
: une sélection (SFW) de mots anglais de quatre lettres.En cas de nouvel échec, il se rabat sur "lorem_ipsum.txt"
.
L'option obfuscation_max_length
permet de limiter la longueur des libellés de substitution (par défaut, c'est la longueur du plus long mot du faux-texte).
Notez enfin que l'algorithme s'assure que la distance de Damerau-Levenshtein entre deux libellés de substitution quelconques est d'au moins 3 (valeur par défaut du paramètre obfuscation_min_distance
). 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 vous empêcheront pas de retrouver son intention première. Par exemple, au cours du processus d'obfuscation suivant:
In [ ]:
%%mocodo --obfuscate=four_letter_words --seed=42 --no_mcd
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
L'algorithme a écarté les mots dish (confusion possible avec wash), folk (confusion possible avec milk), peer (confusion possible avec ever), hall (confusion possible avec haul), baby (confusion possible avec lady).
Le tracé réalisé par Mocodo pour des MCD de plusieurs rangées laisse parfois à désirer :
In [ ]:
%%mocodo
Quis, 01 Risus, 1N Ipsum a
Ipsum a: semper, massa
Odio, 1N Ipsum a, 0N Posuere: suscipit
Ac, 01 Risus, 0N Risus
Risus: euismod, semper, dederit, ribandum
Diam leo, 1N Risus, 0N Posuere
Posuere: semper, massa
Pretium, 0N Posuere, 0N Posuere
Curae, 0N Risus, 0N Tellus: pede
METUS, 11 Tellus, 0N Posuere
Ultrices: libero
Lorem, 0N Ultrices, 0N Tellus, 0N Risus: lacus, feugiat
Tellus: domus, tempero
On voit que, par défaut, Mocodo centre les rangées qui contiennent moins de boîtes que les autres. Cela donne un bon résultat pour la première rangée, mais pas pour la troisième.
L'utilisateur peut cependant spécifier les espacements qu'il désire en complétant les rangées les moins fournies, par des boîtes invisibles dont le seul rôle est de « pousser » les autres à l'emplacement voulu. Ainsi, il va préciser que l'association Curae doit commencer sur la troisième colonne en insérant des lignes réduites au caractère deux-points, et en profiter pour insérer un espace entre Lorem et Tellus :
In [ ]:
%%mocodo
Quis, 01 Risus, 1N Ipsum a
Ipsum a: semper, massa
Odio, 1N Ipsum a, 0N Posuere: suscipit
Ac, 01 Risus, 0N Risus
Risus: euismod, semper, dederit, ribandum
Diam leo, 1N Risus, 0N Posuere
Posuere: semper, massa
Pretium, 0N Posuere, 0N Posuere
:
:
Curae, 0N Risus, 0N Tellus: pede
METUS, 11 Tellus, 0N Posuere
:
Ultrices: libero
Lorem, 0N Ultrices, 0N Tellus, 0N Risus: lacus, feugiat
:
Tellus: domus, tempero
Il est possible de « compresser » les suites de deux-points en supprimant les retours-chariots, autrement dit, de remplacer $n$ lignes réduites à deux-points par une ligne réduite à une séquence de $n$ deux-points. Ce raccourci est illustré dans le prochain exemple.
Nouveauté de la version 2.2. On cherche en général à faire tenir le MCD dans la plus petite grille possible, tout en maintenant un rapport « équilibré » entre hauteur et largeur. Par exemple, un MCD de 13 boîtes (entités ou associations) peut tenir dans les grilles:
Les deux premières grilles étant non équilibrées, on retiendra la plus petite des suivantes, de dimensions $5\times3$.
La table ci-dessous énumère les dimensions des grilles minimales d'équilibre supérieur à 0,5 pour tous les MCD comportant moins de 100 boîtes:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | ||||||||||||
2 | 2, 3, 4 | 5, 6 | |||||||||||
3 | 7, 8, 9 | 10, 11, 12 | 13, 14, 15 | ||||||||||
4 | 16 | 17, 18, 19, 20 | 21, 22, 23, 24 | 26, 27, 28 | |||||||||
5 | 25 | 29, 30 | 31, 32, 33, 34, 35 | 37, 38, 39, 40 | 43, 44, 45 | ||||||||
6 | 36 | 41, 42 | 46, 47, 48 | 50, 51, 52, 53, 54 | 57, 58, 59, 60 | 65, 66 | |||||||
7 | 49 | 55, 56 | 61, 62, 63 | 67, 68, 69, 70 | 73, 74, 75, 76, 77 | 82, 83, 84 | 91 | ||||||
8 | 64 | 71, 72 | 78, 79, 80 | 85, 86, 87, 88 | 92, 93, 94, 95, 96 | ||||||||
9 | 81 | 89, 90 | 97, 98, 99 |
On peut y vérifier par exemple que le MCD de taille 13 se trouve effectivement aux coordonnées (5, 3).
Avec l'option --fit
, Mocodo est maintenant capable de reformater automatiquement un MCD pour le faire entrer dans la grille minimale correspondante:
In [ ]:
%%mocodo --fit
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
L'algorithme se contente de supprimer ou d'insérer des sauts de ligne dans le texte-source, sans modifier l'ordre des clauses. On devra donc encore en général opérer sur le résultat un réarrangement automatique (voir plus loin).
In [ ]:
%%mocodo --arrange
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
::
Si ce réarrangement échoue ou laisse à désirer, il est possible de spécifier chacune des ièmes grilles suivantes avec l'option --fit=i
:
In [ ]:
%%mocodo --fit=1
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
In [ ]:
%%mocodo --arrange
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
:::
Remarques.
--fit
définit une grille trop grande, le réarrangement automatique retombe fréquemment sur une sous-grille de celle-ci.--fit
et --arrange
.
In [ ]:
%%mocodo
Augue, 0N Congue, 0N Congue
Congue: ligula, tellus
DF, 11 Nonummy, 0N Congue
Nonummy: consequat, ligula
Posuere: pede
:
Metus, 1N Elit, 0N Congue: nibh
Ipsum, 1N Blandit, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
:
Elit: ligula, tellus
Lacus, 01 Blandit, 1N Elit
Blandit: consequat, ligula, nibh, consequat
Bibendum, 01 Blandit, 0N Blandit
Nouveauté de la version 2.1. Mocodo est capable de détecter certaines configurations de pattes dont les cardinalités présentent un risque élevé de collision. Il procède alors à deux types d'ajustements:
Ces ajustements automatiques résolvent les problèmes les plus courants. Toutefois, étant antérieurs au tracé proprement dit, ils peuvent seulement minimiser les risques de collision, et non les prévenir totalement. Ils peuvent même en produire d'autres. Ainsi, autour des entités particulièrement pattues, des collisions qui ne se seraient pas produites par défaut seront parfois observées. L'utilisateur a alors deux possibilités:
--flex
(par défaut, 0.75
) pour réduire la courbure de l'inflexion automatique, en allant jusqu'à 0
pour la désactiver totalement (exemple).Mocodo, au lieu de générer directement un dessin statique, génère d'abord un script Python, qui lui-même générera le dessin attendu. Cela se fait de façon transparente, sans intervention de l'utilisateur. L'avantage de cette couche supplémentaire est que le script intermédiaire exprime la plupart des positions, non en absolu, mais en relation à d'autres positions, peu nombreuses et qui constituent de fait les véritables paramètres du dessin. Sa capacité à évaluer des formules le rend beaucoup plus souple et puissant que si les valeurs résultantes étaient stockées en dur.
Le script intermédiaire s'appelle par défaut:
sandbox_nodebox.py
sur Mac OS X avec NodeBox 1.x installé ;sandbox_svg.py
dans toutes les autres configurations.Montrons comment retoucher le MCD suivant:
In [ ]:
%%mocodo --shapes trebuchet
Velit, 0N Blandit, 0N Nonummy: sollicitudin
Blandit: consequat, ligula, nibh, consequat
:::
Nonummy: consequat, ligula
Vivamus, 0N Nonummy, 0N Blandit: eleifend, iaculis
Si on ouvre le script intermédiaire avec un éditeur de texte, on verra que ses premières instructions exposent les principaux paramètres de position:
(width,height) = (384,233)
cx = {
u"Velit" : 192,
u"Blandit": 47,
u"Nonummy": 337,
u"Vivamus": 192,
}
cy = {
u"Velit" : 35,
u"Blandit": 112,
u"Nonummy": 112,
u"Vivamus": 189,
}
shift = {
u"Velit,Blandit" : 0,
u"Velit,Nonummy" : 0,
u"Vivamus,Nonummy": 0,
u"Vivamus,Blandit": 0,
}
width
et height
définit la taille du MCD;cx
et cy
, les abscisses et ordonnées des centres des boîtes;shift
, les positions relatives des cardinalités par rapport à leur position par défaut.Voici les modifications que nous décidons d'apporter au fichier (ignorez la première ligne):
In [ ]:
%%file mocodo_notebook/replace.tmp
(width,height) = (340,153) # réduire de 40 pixels en largeur et de 80 pixels en hauteur
cx = {
u"Velit" : 170, # décaler de 20 pixels vers la gauche
u"Blandit": 47,
u"Nonummy": 293, # décaler de 40 pixels vers la gauche
u"Vivamus": 170, # décaler de 20 pixels vers la gauche
}
cy = {
u"Velit" : 35,
u"Blandit": 72, # remonter de 40 pixels
u"Nonummy": 72, # remonter de 40 pixels
u"Vivamus": 109, # remonter de 40 pixels
}
shift = {
u"Velit,Blandit" : -30, # mettre la cardinalité au-dessus de la patte
u"Velit,Nonummy" : -30, # mettre la cardinalité au-dessus de la patte
u"Vivamus,Nonummy": 0,
u"Vivamus,Blandit": 0,
}
Sous Nodebox, il suffit alors de choisir Run dans le menu Python.
Si vous travaillez avec des fichiers SVG, il faut exécuter le script ..._svg.py
. Il regénère alors le fichier SVG qui contient le dessin. Il ne reste plus qu'à l'ouvrir, par exemple avec un navigateur.
Les lignes suivantes (qu'il est inutile de comprendre) permettent de faire la même chose à l'intérieur de cette documentation.
In [ ]:
!cd mocodo_notebook ; sed -i.tmp -e '10,28d' -e '8r replace.tmp' sandbox_svg.py ; rm *.tmp
!python mocodo_notebook/sandbox_svg.py
from IPython.core.display import SVG
SVG("mocodo_notebook/sandbox.svg")
Out[ ]:
Selon le même principe, on peut faire glisser les flèches le long des arcs (dictionnaire ratio
) ou modifier les couleurs (dictionnaire colors
).
Cette technique inhabituelle nous semble une application naturelle du dynamisme du langage Python. Mais c'est à vous de décider si vous êtes plus efficace en ajustant des valeurs numériques, ou en faisant glisser des objets dans votre cliquodrome favori, comme décrit dans la section suivante.
Un fichier SVG peut être visualisé dans tout navigateur moderne.
Pour aller au-delà de la simple visualisation, il faudra faire appel à un logiciel de dessin vectoriel dédié, comme Inkscape (libre) ou Adobe Illustrator, Freehand, CorelDRAW, etc. Les éléments du fichier SVG produit pourront alors être repositionnés à la souris. Certains sont associés, pour permettre leur déplacement en bloc. Dans la version actuelle, les liens ne suivent pas ces déplacements, ce qui peut obliger à des manipulations supplémentaires.
Mocodo permet de calculer facilement le symétrique d'un MCD, par exemple celui donné ci-dessous:
In [ ]:
%%mocodo
Assistas, 01 Hci poilu, 0N Hci poilu
Hci poilu: graffiti, champignon, troussa, graffiti
Rayonnait, 0N Hci poilu, 0N Lappa: monobloc
Brisa: souffrait
Pillards, 0N Brisa, 0N Lappa, 0N Hci poilu: disions, lascar
Lappa: graffiti, champignon
Puni, 11 Lappa, 0N Lappa
Nouveauté de la version 2.0.20. Pour remplacer le texte de la cellule par le résultat de son évaluation, ajoutez l'option --replace
.
In [ ]:
%%mocodo --flip=v
Assistas, 01 Hci poilu, 0N Hci poilu
Hci poilu: graffiti, champignon, troussa, graffiti
Rayonnait, 0N Hci poilu, 0N Lappa: monobloc
Brisa: souffrait
Pillards, 0N Brisa, 0N Lappa, 0N Hci poilu: disions, lascar
Lappa: graffiti, champignon
Puni, 11 Lappa, 0N Lappa
In [ ]:
%%mocodo --flip=h
Assistas, 01 Hci poilu, 0N Hci poilu
Hci poilu: graffiti, champignon, troussa, graffiti
Rayonnait, 0N Hci poilu, 0N Lappa: monobloc
Brisa: souffrait
Pillards, 0N Brisa, 0N Lappa, 0N Hci poilu: disions, lascar
Lappa: graffiti, champignon
Puni, 11 Lappa, 0N Lappa
In [ ]:
%%mocodo --flip=d
Assistas, 01 Hci poilu, 0N Hci poilu
Hci poilu: graffiti, champignon, troussa, graffiti
Rayonnait, 0N Hci poilu, 0N Lappa: monobloc
Brisa: souffrait
Pillards, 0N Brisa, 0N Lappa, 0N Hci poilu: disions, lascar
Lappa: graffiti, champignon
Puni, 11 Lappa, 0N Lappa
Pour une symétrie selon l'anti-diagonale, appliquer successivement les trois symétries précédentes dans n'importe quel ordre.
La transposition peut être utilisée pour réaliser plus facilement certaines opérations d'édition en colonne, en particulier sous Mocodo online. Par exemple, supposons que l'on souhaite décaler vers le haut la dernière colonne du MCD ci-dessous:
In [ ]:
%%mocodo --flex=0
AMET, 11> LOREM, 01 CONSECTETUER: adipiscing
CONSECTETUER: elit, sed
TORTOR, 0N RISUS, 11 DIGNISSIM, 1N CONSECTETUER: nec
DF, 11 RISUS, 0N RISUS
LOREM: ipsum, dolor, sit
SOLLICITUDIN, 0N SUSPENDISSE, 0N CONSECTETUER, 0N LOREM: lectus
DIGNISSIM: ligula, massa, varius
RISUS: ultricies, _cras, elementum
DF1, 11 LOREM, 1N SUSPENDISSE
SUSPENDISSE: diam
MAECENAS, 1N DIGNISSIM, 1N DIGNISSIM
SEMPER, 0N RISUS, 1N DIGNISSIM
On commence par transposer:
In [ ]:
%%mocodo --no_mcd --flip=d
AMET, 11> LOREM, 01 CONSECTETUER: adipiscing
CONSECTETUER: elit, sed
TORTOR, 0N RISUS, 11 DIGNISSIM, 1N CONSECTETUER: nec
DF, 11 RISUS, 0N RISUS
LOREM: ipsum, dolor, sit
SOLLICITUDIN, 0N SUSPENDISSE, 0N CONSECTETUER, 0N LOREM: lectus
DIGNISSIM: ligula, massa, varius
RISUS: ultricies, _cras, elementum
DF1, 11 LOREM, 1N SUSPENDISSE
SUSPENDISSE: diam
MAECENAS, 1N DIGNISSIM, 1N DIGNISSIM
SEMPER, 0N RISUS, 1N DIGNISSIM
Il suffit alors d'insérer un deux-points au début de chacune des trois premières rangées, puis de retransposer dans l'autre sens:
In [ ]:
%%mocodo --flip=d
:
AMET, 11> LOREM, 01 CONSECTETUER: adipiscing
LOREM: ipsum, dolor, sit
DF1, 11 LOREM, 1N SUSPENDISSE
:
CONSECTETUER: elit, sed
SOLLICITUDIN, 0N SUSPENDISSE, 0N CONSECTETUER, 0N LOREM: lectus
SUSPENDISSE: diam
:
TORTOR, 0N RISUS, 11 DIGNISSIM, 1N CONSECTETUER: nec
DIGNISSIM: ligula, massa, varius
MAECENAS, 1N DIGNISSIM, 1N DIGNISSIM
DF, 11 RISUS, 0N RISUS
RISUS: ultricies, _cras, elementum
SEMPER, 0N RISUS, 1N DIGNISSIM
On peut se convaincre en examinant le nouveau texte d'entrée que le résultat aurait été beaucoup plus pénible à obtenir en procédant directement.
Il est possible de demander à Mocodo de chercher tout seul une « bonne » permutation des boîtes, ce qui à la main deviendrait vite difficile.
Le critère que nous avons retenu pour évaluer la qualité d'une permutation est double:
Trois algorithmes sont fournis:
bb
, pour Branch & Bound), qui ne trouve que des solutions satisfaisant aux deux critères;ga
, pour Genetic Algorithm), réservé aux cas où il est impossible de satisfaire au premier critère. L'algorithme va alors chercher des solutions où les liens se coupent seulement le moins possible;lp
, pour Linear Programming), mais reposant sur un solveur générique (actuellement, CPLEX ou Gurobi).Nouveauté de la version 2.0.20. Pour remplacer le texte de la cellule par le résultat de son évaluation, ajoutez l'option --replace
.
Voici à titre d'exemple un résultat trouvé par l'algorithme exact, suivi du MCD correspondant:
In [ ]:
%%mocodo --arrange --seed=1
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
Le réarrangement automatique se fera toujours à l'intérieur d'une grille ayant autant de colonnes et de rangées que le texte de départ (ici, $4\times5$). On peut quelquefois essayer de réduire cette grille. Par exemple, le MCD ci-dessus comporte 13 boîtes. Elles pourraient donc théoriquement tenir dans une grille $5\times3=15$. Modifions le texte à la main pour avoir 3 blocs d'au plus 5 lignes, et vérifier qu'un tel réarrangement est possible:
In [ ]:
%%mocodo --arrange --seed=4
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
Le réarrangement dit organique consiste à choisir une première boîte au hasard, puis à essayer d'agréger les autres sans se préoccuper de contenir le tout dans une grille prédéterminée.
In [ ]:
%%mocodo --arrange --organic --seed=14
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
Cela donne un autre plongement du MCD sur une grille $4\times5$, ce qui comme on l'a vu n'est pas optimal. En fait, le résultat d'une réorganisation organique peut souvent être trivialement amélioré, par exemple ici en faisant pivoter Augue et en décalant DF:
In [ ]:
%%mocodo
Augue, 0N Congue, 0N Congue
Congue: ligula, tellus
:
DF, 11 Nonummy, 0N Congue
Metus, 1N Elit, 0N Congue: nibh
Ipsum, 1N Blandit, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
Nonummy: consequat, ligula
Elit: ligula, tellus
Lacus, 01 Blandit, 1N Elit
Blandit: consequat, ligula, nibh, consequat
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
::
Bibendum, 01 Blandit, 0N Blandit
Posuere: pede
De fait, le réarrangement organique fournit souvent un bon point de départ pour chercher soi-même une permutation plus esthétique ou mettant en évidence certaines propriétés du MCD.
Pour permettre au programme de rendre plus rapidement de bonnes solutions, on a borné arbitrairement le nombre d'appels à la fonction chargée de construire une permutation à partir du placement de la première boîte. De ce fait, l'algorithme n'est plus exact, en ce sens que la meilleure solution peut occasionnellement lui échapper. Si vous soupçonnez que c'est le cas, faites un autre essai, éventuellement en augmentant la borne (par défaut 10000):
mocodo --arrange --call_limit=100000
Et pour en avoir complètement le cœur net, lancez le solveur de programmes linéaires:
mocodo --arrange=lp
D'autre part, le réarrangement exact ne fonctionnera jamais sur les MCD:
Rappelons qu'un graphe est dit planaire lorsqu'il en existe au moins un arrangement sans croisement. Le graphe non planaire comportant le plus petit nombre de liens est connu sous le nom de $K_{3,3}$:
In [ ]:
%%mocodo
DIGNISSIM: nec sem, nunc, vulputate
IMPERDIET: a praesent, nibh, semper
TINCIDUNT: faucibus, orci, cursus
RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
Son réarrangement échoue donc:
In [ ]:
%%mocodo --arrange
DIGNISSIM: nec sem, nunc, vulputate
IMPERDIET: a praesent, nibh, semper
TINCIDUNT: faucibus, orci, cursus
RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
Dans tous ces cas, on pourra se rabattre sur l'heuristique. Celle-ci, au lieu d'interdire les croisements, cherche simplement à en minimiser le nombre.
In [ ]:
%%mocodo --arrange=ga --seed=42
DIGNISSIM: nec sem, nunc, vulputate
IMPERDIET: a praesent, nibh, semper
TINCIDUNT: faucibus, orci, cursus
RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
L'amélioration ne saute pas forcément aux yeux, mais il n'y a plus que 3 croisements au lieu de 9. Ce plongement constitue en tout cas un bon point de départ pour un réarrangement manuel. Pour arriver à une représentation lisible, il ne reste plus qu'à insérer quelques boîtes invisibles:
In [ ]:
%%mocodo
RHONCUS, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
DIGNISSIM: nec sem, nunc, vulputate
:::
IMPERDIET: a praesent, nibh, semper
SODALES, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
:::
QUIS ENIM, 1N DIGNISSIM, 1N IMPERDIET, 1N TINCIDUNT
TINCIDUNT: faucibus, orci, cursus
Nouveauté de la version 2.2. Cette méthode, invoquée avec le paramètre arrange=lp
, trouvera nécessairement l'une des meilleures solutions, pour peu que celle-ci existe et que vous ayez du temps devant vous.
L'idée est de convertir le problème en programme linaire, de l'envoyer à un solveur externe, et de récupérer le résultat à la fin.
Actuellement, le solveur peut être CPLEX:
In [ ]:
%%mocodo --arrange=lp --engine=cplex
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
... Ou Gurobi:
In [ ]:
%%mocodo --arrange=lp --engine=gurobi
Lacus, 01 Blandit, 1N Elit
Elit: ligula, tellus
Metus, 1N Elit, 0N Congue: nibh
Bibendum, 01 Blandit, 0N Blandit
Blandit: consequat, ligula, nibh, consequat
Ipsum, 1N Blandit, 0N Congue
Congue: ligula, tellus
Augue, 0N Congue, 0N Congue
Velit, 0N Blandit, 0N Nonummy: sollicitudin
DF, 11 Nonummy, 0N Congue
Posuere: pede
Vivamus, 0N Posuere, 0N Nonummy, 0N Blandit: eleifend, iaculis
Nonummy: consequat, ligula
Remarques.
L'exportation est déléguée à votre éditeur SVG ou à Nodebox. Le format PDF assure la meilleure qualité, aussi bien pour la visualisation sur écran, que pour la projection ou l'impression. Si vous devez absolument utiliser un format bitmap, préférez PNG ou GIF.
Le passage au relationnel se fait en deux étapes:
La séquence d'opérations suivante est réalisée:
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).
Illustrons le premier cas du troisième point sur un MCD comportant des associations triple, double et réflexive dont toutes les cardinalités maximales sont à N.
In [ ]:
%%mocodo --mld
LACUS: blandit, elit
LIGULA, 0N LACUS, 1N EROS, 0N TELLUS: metus
EROS: congue, nibh, tincidunt
BIDENDUM, 0N TELLUS, 1N TELLUS: consequat
TELLUS: integer, odio
FAUCIBUS, 1N TELLUS, 0N EROS: ipsum
Notez la désambiguïsation automatique par numérotation du deuxième attribut de BIBENDUM.
Illustrons l'autre cas sur un MCD quasiment identique, à ceci près que certaines cardinalités maximales ont été ramenées à 1. En tant que dépendances fonctionnelles, toutes les associations vont alors disparaître.
In [ ]:
%%mocodo --mld
LACUS: blandit, elit
LIGULA, 11 LACUS, 1N EROS, 0N TELLUS: metus
EROS: congue, nibh, tincidunt
BIDENDUM, 0N TELLUS, 11 TELLUS: consequat
TELLUS: integer, odio
FAUCIBUS, 11 TELLUS, 01 EROS: ipsum
Notez les points suivants:
Les deux alternatives mentionnées, plus orthodoxes mais plus lourdes, produisent de toute façon le même schéma relationnel. Autre point litigieux, cette fois non pris en charge par Mocodo: dans les dépendances fonctionnelles à double sens ((1,1) des deux côtés), la priorité est donnée de façon non spécifiée à l'un des (1,1).
Nouveauté. Les renforcements en cascade sont correctement gérés dans tous les cas, et les renforcements cycliques produisent un message d'erreur.
In [ ]:
%%mocodo --mld --relations diagram
Appartement: num appart., nb pièces appart.
Composer, 0N Étage, _11 Appartement
Étage: num étage, nb appart. étage
Appartenir, 1N Immeuble, _11 Étage
Immeuble: num immeuble, nb étages immeuble
Se situer, 0N Rue, _11 Immeuble
Rue: code rue, nom rue
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.
Ce processus apparaît clairement sur le diagramme relationnel généré par la commande précédente:
In [ ]:
%mocodo --input mocodo_notebook/sandbox.mld
Mocodo permet de modifier légèrement le nom d'une clef étrangère, de façon à réintroduire la sémantique perdue lors de la disparition de l'association de dépendance fonctionnelle par laquelle elle a migré.
In [ ]:
%%mocodo --mld
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
Par exemple, ci-dessus, la conversion en relationnel produit dans la relation ÉTUDIANT des clefs étrangères date et date.1 qui ne peuvent être laissées en l'état. Éventuellement, on peut souhaiter expliciter la présence d'un numéro d'enseignant dans ÉTUDIANT.
Dans les deux cas, il suffit d'employer le système d'annotation de pattes introduit plus haut:
In [ ]:
%%mocodo --mld --no_mcd
Soutenir, 01 Étudiant, 0N [soutenance] Date: note stage
Étudiant: num. étudiant, nom, coordonnées
Date: date
Répondre de, 0N [visite] Date, 11 Étudiant, 0N [responsable] Enseignant
Enseignant: num. enseignant, nom, coordonnées
De façon moins cruciale, la technique s'applique aussi aux autres types d'association:
In [ ]:
%%mocodo --mld
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, 0N [ayant commandé] CLIENT, 11 [annotation ignorée] COMMANDE
COMMANDE: Num. commande, Date, Montant
INCLURE, 1N [passée] COMMANDE, 0N [commandé] PRODUIT: Quantité
PRODUIT: Réf. produit, Libellé, Prix unitaire
Pour désactiver cette fonctionnalité (notamment dans le cas où vous annotez chaque cardinalité d'une explication destinée aux novices), passez l'option --disambiguation=numbers_only
.
Les règles de gestion peuvent parfois conduire à remettre en cause l'application mécanique de l'algorithme de conversion. Mocodo est capable de traiter certaines exceptions, pourvu qu'elles lui soient indiquées.
Il arrive qu'un sous-ensemble strict de l'ensemble des identifiants des entités mises en jeu dans une association dont toutes les pattes portent la cardinalité N, suffise à constituer la clef primaire de la table issue de cette association: cela se fait facilement au niveau relationnel en faisant perdre leur caractère identifiant aux clefs n'appartenant pas à ce sous-ensemble. Pour obtenir le même résultat avec Mocodo, il suffit de préfixer les entités concernées par une barre oblique.
In [ ]:
%%mocodo --mld
LACUS: blandit, elit
LIGULA, 0N LACUS, 1N /EROS, 0N TELLUS: metus
EROS: congue, nibh, tincidunt
TELLUS: integer, odio
La barre oblique de EROS n'apparaît pas dans le MCD, mais conduit à la réduction de la clef primaire de LIGULA aux seuls identifiants des deux autres entités mises en jeu.
On a vu qu'en l'absence d'une cardinalité (1,1), Mocodo traitait par défaut la cardinalité (0,1) comme une dépendance fonctionnelle. Or, lorsque le 0 est grand devant le 1 en termes de fréquence d'apparition, la plupart des occurrences de la clef étrangère ainsi constituée restent vides. On aura alors intérêt à forcer la conversion de l'association en table. Cela se fait en préfixant d'une barre oblique l'une au moins des entités non distinguées par le (0,1).
In [ ]:
%%mocodo --mld
LACUS: blandit, elit
LIGULA, 01 LACUS, 1N /EROS: metus
EROS: congue, nibh, tincidunt
La représentation interne peut être dérivée en représentation externe par l'application d'une spécification de format, ou gabarit (template en anglais). Les schémas relationnels affichés au-dessous des diagrammes conceptuels dans la présente section sont un exemple de sortie au format HTML.
Dans sa représentation la plus compacte, un schéma relationnel s'écrit comme une suite de lignes de la forme:
RELATION ( clef_primaire, attribut_1, attribut_2, ...)
Sauf mention contraire, les MLD affichés dans ce document ont été produits par Mocodo au format HTML. Pour un autre exemple, voici la génération et l'affichage d'une sortie $\mathrm\LaTeX$:
In [ ]:
%%mocodo --relations latex
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
In [ ]:
# %load mocodo_notebook/sandbox.tex
% Copy this before \begin{document}
\usepackage[normalem]{ulem}
\newenvironment{mld}
{\par\begin{minipage}{\linewidth}\begin{tabular}{rp{0.7\linewidth}}}
{\end{tabular}\end{minipage}\par}
\newcommand{\relat}[1]{\textsc{#1}}
\newcommand{\attr}[1]{\emph{#1}}
\newcommand{\prim}[1]{\uline{#1}}
\newcommand{\foreign}[1]{\#\textsl{#1}}
% Copy that after \begin{document}
\begin{mld}
Client & (\prim{Réf. client}, \attr{Nom}, \attr{Prénom}, \attr{Adresse})\\
Commande & (\prim{Num commande}, \attr{Date}, \attr{Montant}, \foreign{Réf. client})\\
Inclure & (\foreign{\prim{Num commande}}, \foreign{\prim{Réf. produit}}, \attr{Quantité})\\
Produit & (\prim{Réf. produit}, \attr{Libellé}, \attr{Prix unitaire})\\
\end{mld}
Les formats linéaires actuellement pris en charge par Mocodo sont les suivants:
Nom | Argument | Usage du fichier généré |
---|---|---|
HTML | html | À ouvrir directement avec un navigateur internet ou un programme de traitement de texte (dont Microsoft Word, OpenOffice, Apple Pages, etc.). Implicite dans un Notebook. |
$\mathrm\LaTeX$ | latex | À compiler sous $\mathrm\LaTeX$ pour une sortie de haute qualité aux formats PDF ou PostScript. |
Markdown | markdown | À coller dans une cellule de Notebook, dans un champ textuel de GitHub ou Stack Overflow, ou à ouvrir avec l'un des nombreux éditeurs Markdown existants. |
Texte brut | text | À ouvrir directement avec un éditeur de texte Unicode. |
Txt2tags | txt2tags | À compiler avec le générateur de documents Txt2tags pour une conversion dans de nombreux autres formats: HTML, XHTML, SGML, LaTeX, Lout, Man page, Wikipedia, Google Code Wiki, DokuWiki, MoinMoin, MagicPoint, PageMaker, texte brut. Non disponible sous Mocodo online. |
Deux de ces formats, HTML et Markdown, disposent maintenant d'une version augmentée d'explications détaillées du mécanisme du passage au relationnel. Ce type de sortie, adaptable par l'enseignant, peut être utile aux étudiants qui souhaitent réviser ou travailler en autonomie.
In [ ]:
%%mocodo --relations markdown_verbose
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
In [ ]:
# %load mocodo_notebook/sandbox_verbose.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)
Tout ce texte est généré automatiquement, mais avec des raffinements destinés à le rendre plus lisible pour un humain. Par exemple, les trois attributs non identifiants de l'entité CLIENT sont décrits en une seule ligne au lieu de trois.
La plupart des SGBD offrent une représentation hybride (graphique / texte) de la base, sous la forme d'un ensemble de tables rectangulaires liées par des flèches. Mocodo génère maintenant un fichier d'extension .mld
qu'il est capable de reprendre en entrée pour tracer ce type de graphe.
In [ ]:
%%mocodo --relations diagram
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
In [ ]:
%mocodo --input mocodo_notebook/sandbox.mld
In [ ]:
# %load mocodo_notebook/sandbox.mld
%%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
:
Si l'on ouvre le fichier généré (cf. ci-dessus), on constate que la syntaxe d'un MLD est 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 qui se notent: E1: ... a1->E2->a2
.
Les boîtes invisibles automatiquement insérées une colonne sur deux aèrent le résultat de façon à laisser de la place aux flèches.
Remarquons que ce pseudo-MCD est un « point fixe » de l'opération de passage au relationnel, c'est-à-dire qu'il redonne le même MLD que le MCD de départ:
In [ ]:
%%mocodo --relations diagram
:
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
:
Mais cette fois, comme le « MCD » d'entrée ne comporte aucune association, le diagramme relationnel généré ne comporte aucune flèche.
In [ ]:
%mocodo --input mocodo_notebook/sandbox.mld
Le reprendre comme texte d'entrée produit donc le même diagramme, mais sans les flèches. Leur rétablissement pourrait faire l'objet d'un exercice facile.
Sous Mocodo online, vous obtiendrez le premier diagramme relationnel en trois étapes:
Les relations sont placées dans le même ordre que les boîtes du MCD d'origine, mais vous devrez souvent les réorganiser (automatiquement ou manuellement) pour obtenir un résultat plus esthétique.
Le diagramme relationnel sans flèches s'obtient en répétant les étapes 2 et 3.
Les versions successives des différents fichiers étant écrasées à chaque regénération, veillez à télécharger l'archive après chaque étape si vous souhaitez garder l'ensemble.
Limitation. Les clefs étrangères composites sont actuellement représentées comme si elles étaient séparées (autant de flèches que de parties).
Nouveauté de la version 2.3.5. Les tables réduites à une clef primaire non composite sont supprimées et les éventuelles clefs étrangères correspondantes perdent leur caractère étranger. Ainsi, dans le diagramme relationnel de l'introduction, les tables MATIÈRE et DATE ont disparu et les clefs étrangères libellé matière et date ne sont pas préfixées d'un dièse ou accompagnées d'une flèche.
Mocodo est livré avec des fichiers de spécification pour les dialectes SQL suivants:
SGBD | Argument | Suffixe et extension |
---|---|---|
MySQL | --relations mysql |
"_mysql.sql" |
Oracle | --relations oracle |
"_oracle.sql" |
PostgreSQL | --relations postgresql |
"_postgresql.sql" |
SQLite | --relations sqlite |
"_sqlite.sql" |
Notez que les contraintes de clefs étrangères sont ajoutées après création de l'ensemble des tables, sauf pour SQLite, qui n'impose pas d'ordre de création spécifique, et qui de toute façon ne prend pas en charge ce type d'altération.
Le type de données peut être inséré entre crochets droits après chaque attribut:
In [ ]:
%%mocodo --title=client_commande_produit --relations=mysql
CLIENT: Réf. client [varchar(8)], Nom [varchar(20)], Adresse [varchar(40)]
DF, 0N CLIENT, 11 COMMANDE
COMMANDE: Num commande [tinyint(4)], Date [date], Montant [decimal(5,2) DEFAULT '0.00']
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité [tinyint(4)]
PRODUIT: Réf. produit [varchar(8)], Libellé [varchar(20)], Prix unitaire [decimal(5,2)]
Quoique ces informations supplémentaires ne soient pas apparues dans le diagramme conceptuel, elles ont été exploitées par la commande, qui a produit dans le répertoire mocodo_notebook
un fichier directement exécutable par MySQL:
In [ ]:
# %load mocodo_notebook/sandbox_mysql.sql
CREATE DATABASE IF NOT EXISTS `CLIENT_COMMANDE_PRODUIT` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `CLIENT_COMMANDE_PRODUIT`;
CREATE TABLE `CLIENT` (
`réf_client` varchar(8),
`nom` varchar(20),
`adresse` varchar(40),
PRIMARY KEY (`réf_client`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `COMMANDE` (
`num_commande` tinyint(4),
`date` date,
`montant` decimal(5,2) DEFAULT '0.00',
`réf_client` varchar(8),
PRIMARY KEY (`num_commande`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `INCLURE` (
`num_commande` tinyint(4),
`réf_produit` varchar(8),
`quantité` tinyint(4),
PRIMARY KEY (`num_commande`, `réf_produit`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `PRODUIT` (
`réf_produit` varchar(8),
`libellé` varchar(20),
`prix_unitaire` decimal(5,2),
PRIMARY KEY (`réf_produit`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `COMMANDE` ADD FOREIGN KEY (`réf_client`) REFERENCES `CLIENT` (`réf_client`);
ALTER TABLE `INCLURE` ADD FOREIGN KEY (`réf_produit`) REFERENCES `PRODUIT` (`réf_produit`);
ALTER TABLE `INCLURE` ADD FOREIGN KEY (`num_commande`) REFERENCES `COMMANDE` (`num_commande`);
In [ ]:
%%mocodo --title=appartements --relations=sqlite
Appartement: num appart., nb pièces appart.
Composer, 0N Étage, _11 Appartement
Étage: num étage, nb appart. étage
Appartenir, 1N Immeuble, _11 Étage
Immeuble: num immeuble, nb étages immeuble
Se situer, 0N Rue, _11 Immeuble
Rue: code rue, nom rue
In [ ]:
# %load mocodo_notebook/sandbox_sqlite.sql
.open "APPARTEMENTS";
CREATE TABLE "APPARTEMENT" (
"code_rue" VARCHAR(42),
"num_immeuble" VARCHAR(42),
"num_étage" VARCHAR(42),
"num_appart" VARCHAR(42),
"nb_pièces_appart" VARCHAR(42),
PRIMARY KEY ("code_rue", "num_immeuble", "num_étage", "num_appart"),
FOREIGN KEY ("code_rue", "num_immeuble", "num_étage") REFERENCES "ÉTAGE" ("code_rue", "num_immeuble", "num_étage")
);
CREATE TABLE "ÉTAGE" (
"code_rue" VARCHAR(42),
"num_immeuble" VARCHAR(42),
"num_étage" VARCHAR(42),
"nb_appart_étage" VARCHAR(42),
PRIMARY KEY ("code_rue", "num_immeuble", "num_étage"),
FOREIGN KEY ("code_rue", "num_immeuble") REFERENCES "IMMEUBLE" ("code_rue", "num_immeuble")
);
CREATE TABLE "IMMEUBLE" (
"code_rue" VARCHAR(42),
"num_immeuble" VARCHAR(42),
"nb_étages_immeuble" VARCHAR(42),
PRIMARY KEY ("code_rue", "num_immeuble"),
FOREIGN KEY ("code_rue") REFERENCES "RUE" ("code_rue")
);
CREATE TABLE "RUE" (
"code_rue" VARCHAR(42),
"nom_rue" VARCHAR(42),
PRIMARY KEY ("code_rue")
);
Qui peut le plus peut le moins: en utilisant un gabarit qui ignore toutes les migrations du passage au relationnel, le même algorithme est capable de construire le dictionnaire des données, à savoir la liste des attributs mis en jeu dans votre MCD, avec leur type ou toute autre annotation placée entre crochets droits après l'attribut.
In [ ]:
%%mocodo --no_mcd --relations=markdown_data_dict
CLIENT: Réf. client [varchar(8)], Nom [varchar(20)], Adresse [varchar(40)]
DF, 0N CLIENT, 11 COMMANDE
COMMANDE: Num commande [tinyint(4)], Date [date], Montant [decimal(5,2) DEFAULT '0.00']
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité [tinyint(4)]
PRODUIT: Réf. produit [varchar(8)], Libellé [varchar(20)], Prix unitaire [decimal(5,2)]
In [ ]:
# %load mocodo_notebook/sandbox_data_dict.md
Attribut | Informations |
---|---|
Réf. client | varchar(8) |
Nom | varchar(20) |
Adresse | varchar(40) |
Num commande | tinyint(4) |
Date | date |
Montant | decimal(5,2) DEFAULT '0.00' |
Quantité | tinyint(4) |
Réf. produit | varchar(8) |
Libellé | varchar(20) |
Prix unitaire | decimal(5,2) |
Si l'une au moins des annotations est omise, la présentation générée sera sensiblement différente:
In [ ]:
%%mocodo --no_mcd --relations=markdown_data_dict
CLIENT: Réf. client, Nom, Prénom, Adresse
PASSER, 0N CLIENT, 11 COMMANDE
COMMANDE: Num commande, Date, Montant
INCLURE, 1N COMMANDE, 0N PRODUIT: Quantité [nombre d'unités d'un produit donné dans une commande donnée]
PRODUIT: Réf. produit, Libellé, Prix unitaire
In [ ]:
# %load mocodo_notebook/sandbox_data_dict.md
L'algorithme de génération d'une sortie dans tel ou tel format est totalement découplé de son entrée. Cela signifie que vous pouvez modifier ou créer un format sans écrire une seule ligne de code, mais en remplissant une espèce de formulaire, ou gabarit, qui est un simple fichier JSON. Si vous n'avez aucune velléité de le faire, vous pouvez sauter cette section. Sinon, accrochez-vous, ça va devenir un peu technique.
Pour apprendre à spécifier un format, le mieux est d'étudier les gabarits livrés dans le dossier relation_templates
. Les quelques indications données ici devraient suffire à vous épargner la lecture du code proprement dit.
Chaque gabarit est un fichier JSON associant des clefs prédéfinies à des valeurs librement modifiables. Dans sa forme la plus simple, à savoir le format « texte brut », le fichier (text.json
) se réduit à trois lignes:
{
"extension": ".txt"
}
La clef "extension"
est en effet la seule clef obligatoire d'un tel fichier. Ici, elle est associée à la valeur ".txt"
.
Les autres clefs possibles, toutes facultatives, appartiennent à quatre catégories:
Catégorie | Forme de la clef | Valeur associée | Description |
---|---|---|---|
Transformation | "transform_..." |
objet | Opère une recherche-remplacement, éventuellement itérée (jusqu'à ce qu'aucun remplacement ne soit plus possible), sur une partie du texte déjà généré. Les champs "search" et "replace " sont obligatoires, le champ "iterated" (booléen) est facultatif. La syntaxe est celle des expressions régulières de Python. |
Composition | "compose_..." |
chaîne de format | Interpole dans une chaîne certains identificateurs prédéfinis par une valeur dépendant du contexte en cours. La syntaxe est celle utilisée par la méthode .format de Python. |
Concaténation | "..._separator" |
chaîne | Concatène une liste de chaînes en les séparant par une chaîne donnée. |
Clef de tri | "..._sorting_key" |
objet | Extrait la clef de tri pour la liste concernée. L'expression régulière "search" contient une ou des parenthèses capturantes qui sont ensuite rappelées dans l'expression "replace" |
Voici les différentes opérations effectuées par l'algorithme, dans l'ordre de son déroulement:
"transform_attribute"
applique une première transformation à chaque attribut (identificateur attribute
). Il s'agit en général de supprimer ou remplacer les caractères interdits par le format-cible. Le résultat est référencé par un nouvel identificateur, appelé "raw_label"
."raw_label_lowercase"
(minuscules), "raw_label_uppercase"
(majuscules) et "raw_label_titlecase"
(majuscules initiales)."compose_label_disambiguated_by_annotation"
crée sous le nom de "label"
une copie de "raw_label"
, en introduisant en plus dans les clefs étrangères les annotations des pattes correspondantes. La valeur par défaut est "{raw_label} {leg_annotation}"
, mais pour plus de liberté on peut très bien imaginer de remplacer le label par l'annotation elle-même (avec "{leg_annotation}"
). Cette composition est optionnelle: pour la désactiver, passer l'option disambiguation=numbers_only
."compose_label_disambiguated_by_number"
différencie les libellés homonymes d'une même relation en leur ajoutant un numéro. Par exemple, et c'est la valeur par défaut, pour suffixer le libellé par un point suivi de ce numéro, on écrira: "{label}.{disambiguation_number}"
. L'identificateur "label"
est mis à jour avec le résultat. C'est lui que l'utilisateur utilisera en général dans la suite de l'algorithme, mais il a encore accès aux variantes précédentes."label_lowercase"
, "label_uppercase"
et "label_titlecase"
."transform_title"
reçoit le nom du MCD. Le résultat et ses capitalisations sont associés aux identificateurs "title"
, "title_lowercase"
, "title_uppercase"
et "title_titlecase"
.Ensuite, pour chacune des relations créées dans la représentation interne:
"transform_relation_name"
applique une transformation au nom de la relation et l'associe, avec ses capitalisations, aux identificateurs "this_relation_name"
, "this_relation_name_lowercase"
, "this_relation_name_uppercase"
et "this_relation_name_titlecase"
."this_relation_number"
.Pour chaque colonne de la relation en cours:
"primary_relation_name"
, "primary_relation_name_lowercase"
, "primary_relation_name_uppercase"
et "primary_relation_name_titlecase"
. Dans le cas contraire, tous ces identificateurs sont associés à la chaîne vide."association_name"
, "association_name_lowercase"
, "association_name_uppercase"
et "association_name_titlecase"
. Dans le cas contraire, tous ces identificateurs sont associés à la chaîne vide."compose_[attribute_nature]"
est appliquée, cf. le paragraphe Composition des attributs selon leur nature. Le résultat est accumulé dans une liste de colonnes, en deux versions: dans l'ordre de leur énumération, ou triée selon la clef spécifiée dans "column_sorting_key"
."column_separator"
joint chacune de ces listes de chaînes et associe le résultat à l'identificateur "columns"
et "sorted_columns"
(respectivement)."compose_relation"
construit une relation complète avec tous ses attributs. Par exemple, et c'est la valeur par défaut, "{this_relation_name} ({columns})"
est utilisé dans les formats linéaires."transform_single_column_relation"
s'applique à ce dernier résultat lorsque la relation est réduite à un seul attribut (l'usage est d'en proposer la suppression en la mettant en commentaire)."transform_relation"
est appliqué systématiquement, et le résultat est accumulé dans une liste de relations, en deux versions: dans l'ordre de leur énumération, ou triée selon la clef spécifiée dans "relation_sorting_key"
."relation_separator"
joint chacune de ces listes de chaînes et associe le résultat à l'identificateur "relations"
et "sorted_relations"
(respectivement)."compose_relational_schema"
construit un schéma relationnel complet avec son titre et toutes ses relations. La valeur par défaut est simplement "{relations}"
."transform_relational_schema"
applique une dernière transformation au schéma complet, et renvoie le résultat final.Mocodo offline est livré avec un gabarit spécialement conçu pour vous aider à en créer de nouveaux. Il vous permet de tester sur n'importe quel MCD la génération d'un objet JSON contenant la valeur de tous les identificateurs disponibles pour la composition au niveau de chaque attribut.
In [ ]:
%%mocodo --title client_commande_produit --relations json
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
Le contexte d'un attribut donne accès à 32 identificateurs:
S'y ajoutent "columns"
, "sorted_columns"
, et "relations"
, "sorted_relations"
, qui n'ont de sens que dans le contexte de "compose_relation"
et "compose_relational_schema"
(respectivement).
Le fichier JSON est trop long pour être listé dans son intégralité ici, mais en voici le début, qui concerne la clef primaire Réf. client de la relation Client de la base _client_commandeproduit.
In [ ]:
# %load -r -38 sandbox.json
{
"title": "client_commande_produit",
"title_lowercase": "client_commande_produit",
"title_uppercase": "CLIENT_COMMANDE_PRODUIT",
"title_titlecase": "Client_commande_produit",
"relations": [
{
"this_relation_name": "CLIENT",
"this_relation_name_lowercase": "client",
"this_relation_name_uppercase": "CLIENT",
"this_relation_name_titlecase": "Client",
"this_relation_number": 1,
"columns": [
{
"attribute": "Réf. client",
"raw_label": "Réf. client",
"raw_label_lowercase": "réf. client",
"raw_label_uppercase": "RÉF. CLIENT",
"raw_label_titlecase": "Réf. client",
"disambiguation_number": null,
"label": "Réf. client",
"label_lowercase": "réf. client",
"label_uppercase": "RÉF. CLIENT",
"label_titlecase": "Réf. client",
"primary": true,
"foreign": false,
"nature": "primary_key",
"data_type": null,
"association_name": null,
"association_name_lower_case": null,
"association_name_uppercase": null,
"association_name_titlecase": null,
"leg_annotation": null,
"primary_relation_name": null,
"primary_relation_name_lowercase": null,
"primary_relation_name_uppercase": null,
"primary_relation_name_titlecase": null
},
Ce fragment est à première vue très redondant. En cas de doute, reportez-vous aux tests relations_tests.py
dans le code-source pour un éventail de cas discriminants.
La composition appliquée à un attribut est au cœur de la construction d'une représentation externe. À cette étape, la représentation interne a permis de distinguer 9 catégories d'attributs, 6 courantes et 3 exceptionnelles. Avant de pouvoir exploiter cette classification, il faut la comprendre en détail. Nous allons la présenter à travers deux exemples, le premier répertoriant tous les cas courants, le second tous les cas exceptionnels.
In [ ]:
%%mocodo --mld
Riot: clue
Into, 11 Form, 1N Riot: goat
Form: land, hide
Tuck, 1N Read, 1N Form: thin
Read: wage
Identificateur | Attribut concerné | Défaut | Exemple |
---|---|---|---|
compose_primary_key |
identifiant resté sur place lors de la transformation d'une entité en table | "_{label}_" |
land de Form |
compose_normal_attribute |
simple attribut resté sur place lors de la transformation d'une entité en table | "{label}" |
hide de Form |
compose_foreign_key |
clef étrangère ayant migré par une dépendance fonctionnelle disparue, tout en perdant son caractère identifiant | "#{label}" |
clue de Form |
compose_foreign_attribute |
attribut étranger ayant migré d'une dépendance fonctionnelle disparue | même valeur que compose_normal_attribute |
goat de Form |
compose_foreign_primary_key |
clef étrangère primaire migré dans une association devenue table, tout en gardant son caractère identifiant | "_#{label}_" |
wage et land de Tuck |
compose_association_attribute |
simple attribut resté sur place lors de la transformation d'une association en table | même valeur que compose_normal_attribute |
thin de Tuck |
In [ ]:
%%mocodo --mld
Riot: clue
Walk, 1N Riot, _11 Hour
Hour: book
Poll, 1N Cast, 1N /Hour
Cast: mere
Army, 1N /Busy, 01 Cast
Busy: fail
Identificateur | Attribut concerné | Défaut | Exemple |
---|---|---|---|
compose_strengthening_primary_key |
clef primaire de renforcement d'une entité faible | même valeur que compose_foreign_primary_key |
clue de Hour |
compose_demoted_foreign_key |
clef étrangère ayant migré dans une association devenue table, mais rétrogradée explicitement au rang de simple attribut | même valeur que compose_foreign_key |
book de Poll |
compose_promoting_foreign_key |
clef étrangère non primaire ayant migré dans une dépendance fonctionnelle explicitement promue au rang de table | même valeur que compose_foreign_key |
fail de Army |
Voici pour référence un gabarit JSON prêt à l'emploi, à partir duquel vous pourrez créer les vôtres. Il comporte l'intégralité des identificateurs disponibles, avec leur valeur par défaut et dans l'ordre de déroulement de l'algorithme:
{
"extension": "requis: pas de valeur par défaut",
"transform_attribute": [],
"transform_title": [],
"transform_data_type": [],
"compose_label_disambiguated_by_annotation": "{raw_label} {leg_annotation}",
"compose_label_disambiguated_by_number": "{label}.{disambiguation_number}",
"compose_primary_key": "_{label}_",
"compose_normal_attribute": "{label}",
"compose_foreign_key": "#{label}",
"compose_foreign_attribute": "par défaut, même valeur que compose_normal_attribute",
"compose_foreign_primary_key": "_#{label}_",
"compose_association_attribute": "par défaut, même valeur que compose_normal_attribute",
"compose_strengthening_primary_key": "par défaut, même valeur que compose_foreign_primary_key",
"compose_demoted_foreign_key": "par défaut, même valeur que compose_foreign_key",
"compose_promoting_foreign_key": "par défaut, même valeur que compose_foreign_key",
"transform_relation_name": [],
"column_sorting_key": {
"search": "(.+)",
"replace": "\\1"
},
"column_separator": ", ",
"compose_relation": "{this_relation_name} ({columns})",
"transform_single_column_relation": [],
"transform_relation": [],
"relation_sorting_key": {
"search": "(.+)",
"replace": "\\1"
},
"relation_separator": "\n",
"compose_relational_schema": "{relations}",
"transform_relational_schema": []
}