ER-diagram
Een entiteit-relatiediagram (afgekort ER-diagram) beschrijft de samenhangende zaken die binnen een bepaald kennisgebied van belang zijn. Een basis-ER-diagram bestaat uit entiteitstypen (om zaken van belang te classificeren) en specificeert de relaties die tussen entiteiten (exemplaren van deze entiteitstypen) kunnen bestaan,Let op: in de praktijk wordt 'entiteitstype' in een ER-diagram bijna altijd afgekort tot 'entiteit'. Zo wordt 'het entiteitstype CUSTOMER' gewoonlijk 'de entiteit CUSTOMER' genoemd. Dit gebruik is zo gangbaar dat andere formuleringen worden afgeraden, maar technisch gezien is een entiteit een abstract exemplaar van een entiteitstype, en het ER-diagram toont juist deze abstracte exemplaren en hun onderlinge relaties. Daarom worden entiteiten altijd met een zelfstandig naamwoord in het enkelvoud genoemd.
Kopiëren
Insluiten
---
title: Order example
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
Entiteitsnamen worden gewoonlijk in hoofdletters geschreven, hoewel er geen erkende standaard voor is en de Mermaid-syntaxis dit niet verplicht stelt.
Relaties tussen entiteiten worden weergegeven met lijnen met eindmarkeringen die de kardinaliteit aangeven. Mermaid gebruikt de meest gangbare kraaienpoot-notatie; de kraaienpoot geeft visueel aan dat de entiteit waarmee deze is verbonden meerdere exemplaren kan hebben.
ER-diagrammen kunnen voor allerlei doeleinden worden gebruikt, van een abstract logisch model zonder enige implementatiedetails tot een fysiek model van relationele databasetabellen. Het opnemen van attribuutdefinities in een ER-diagram helpt bij het begrijpen van het doel en de betekenis van entiteiten; deze attribuutdefinities hoeven niet volledig te zijn, meestal volstaat een klein deel van de attributen. Mermaid staat toe ze te definiëren met hun type en naam.
Kopiëren
Insluiten
erDiagram
CUSTOMER ||--o{ ORDER : places
CUSTOMER {
string name
string custNumber
string sector
}
ORDER ||--|{ LINE-ITEM : contains
ORDER {
int orderNumber
string deliveryAddress
}
LINE-ITEM {
string productCode
int quantity
float pricePerUnit
}
Bij het opnemen van attributen in een ER-diagram moet je beslissen of je vreemde sleutels als attributen opneemt; dit kan afhangen van de mate waarin je de structuur van relationele tabellen wilt weergeven. Als je diagram een logisch model is en niet bedoeld is om een relationele implementatie te suggereren, kun je deze attributen beter weglaten, omdat de associatierelatie al aangeeft hoe de entiteiten met elkaar samenhangen. Een JSON-datastructuur kan bijvoorbeeld een een-op-veel-relatie implementeren met een array zonder attributen voor vreemde sleutels. Op dezelfde manier kan een objectgeoriënteerde programmeertaal verwijzingen of pointers naar collecties gebruiken. Zelfs voor modellen die gericht zijn op een relationele implementatie kan men vinden dat het opnemen van attributen voor vreemde sleutels de informatie uit de relatie dupliceert en geen betekenis aan de entiteit toevoegt.
Syntaxis
Entiteiten en relaties
De Mermaid-syntaxis van ER-diagrammen is compatibel met PlantUML en breidt de functionaliteit voor het labelen van relaties uit. Elke verklaring omvat het volgende:
Kopiëren
Insluiten
<first-entity> [<relationship> <second-entity> : <relationship-label>]
- first-entity is de naam van de eerste entiteit. De naam ondersteunt elk Unicode-teken en mag, tussen dubbele aanhalingstekens, spaties bevatten.
- relationship beschrijft de onderlinge relatie tussen twee entiteiten.
- second-entity is de naam van de andere entiteit.
- relationship-label beschrijft de relatie vanuit het perspectief van de eerste entiteit.
Bijvoorbeeld:
Kopiëren
Insluiten
PROPERTY ||--|{ ROOM : contains
Deze declaratie kan als volgt worden begrepen: één eigendom bevat een of meer kamers, en een kamer behoort tot slechts één eigendom. Het label hier wordt bekeken vanuit de eerste entiteit: een eigendom bevat een kamer, maar een kamer bevat geen eigendom. Vanuit het perspectief van de tweede entiteit is het equivalente label doorgaans eenvoudig af te leiden.
Alleen het deel first-entity is verplicht. Hierdoor is het mogelijk entiteiten zonder relaties weer te geven, wat zeer nuttig is bij het iteratief opbouwen van een diagram. Als andere delen van de verklaring worden opgegeven, zijn alle delen verplicht.
Unicode-tekst
Entiteitsnamen, relaties en attributen ondersteunen allemaal unicode-tekst.
Kopiëren
Insluiten
erDiagram
"This ❤ Unicode"
Relatiesyntaxis
Het relatiedeel van elke verklaring kan in drie subdelen worden opgesplitst:
- De kardinaliteit van de eerste entiteit ten opzichte van de tweede entiteit
- Of de relatie de subentiteit identiteit verleent
- De kardinaliteit van de tweede entiteit ten opzichte van de eerste entiteit
Kardinaliteit is een eigenschap die beschrijft met hoeveel elementen een andere entiteit kan worden geassocieerd. In het bovenstaande voorbeeld kan één PROPERTY worden geassocieerd met een of meer ROOM-exemplaren, terwijl één ROOM met slechts één PROPERTY kan worden geassocieerd. Elke kardinaliteitsmarkering bestaat uit twee tekens; het buitenste teken vertegenwoordigt het maximum en het binnenste teken het minimum. De onderstaande tabel vat de mogelijke kardinaliteiten samen:
| Waarde (links) | Waarde (rechts) | Betekenis |
|---|---|---|
| |o | o| | Nul of een |
| || | || | Precies één |
| }o | o{ | Nul of meer (zonder bovengrens) |
| }| | |{ | Een of meer (zonder bovengrens) |
| Waarde (links) | Waarde (rechts) | Betekenis |
|---|---|---|
| one or zero | one or zero | Nul of een |
| zero or one | zero or one | Nul of een |
| one or more | one or more | Een of meer |
| one or many | one or many | Een of meer |
| many(1) | many(1) | Een of meer |
| 1+ | 1+ | Een of meer |
| zero or more | zero or more | Nul of meer |
| zero or many | zero or many | Nul of meer |
| many(0) | many(0) | Nul of meer |
| 0+ | 0+ | Nul of meer |
| only one | only one | Precies één |
| 1 | 1 | Precies één |
Identificatie
Relaties kunnen identificerend of niet-identificerend zijn en worden respectievelijk met een doorgetrokken of een streeplijn gerenderd. Dit is belangrijk wanneer een van de entiteiten niet zonder de andere kan bestaan. Een verzekeringsmaatschappij die mensen auto's laat besturen, moet bijvoorbeeld gegevens over NAMED-DRIVER opslaan. Bij het modelleren stellen we misschien eerst vast dat een CAR door veel PERSONen kan worden bestuurd en dat een PERSON veel CAR's kan besturen; beide kunnen zonder de ander bestaan, dus dit is een niet-identificerende relatie, die we in Mermaid kunnen aangeven als: PERSON }|..|{ CAR : "driver". Let op de twee punten in het midden van de relatie; deze zorgen ervoor dat tussen de twee entiteiten een streeplijn wordt getekend. Wanneer deze veel-op-veel-relatie echter wordt opgesplitst in twee een-op-veel-relaties, stellen we vast dat NAMED-DRIVER niet kan bestaan zonder PERSON en CAR. Deze relaties worden identificerend en worden met een koppelteken weergegeven, wat overeenkomt met een doorgetrokken lijn:
| Waarde | Alias |
|---|---|
| -- | Identificerend |
| .. | Niet-identificerend |
| Waarde | 别名为 |
|---|---|
| to | Identificerend |
| optionally to | Niet-identificerend |
Kopiëren
Insluiten
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
PERSON }o..o{ NAMED-DRIVER : is
Kopiëren
Insluiten
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
PERSON }o--o{ NAMED-DRIVER : is
Attribuut
Je kunt attributen voor een entiteit definiëren door de entiteitsnaam op te geven, gevolgd door een blok met meerdere type name, waarbij het blok tussen accolades {} staat. Attributen worden in het entiteitsvak weergegeven, bijvoorbeeld:
Kopiëren
Insluiten
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string registrationNumber
string make
string model
}
PERSON ||--o{ NAMED-DRIVER : is
PERSON {
string firstName
string lastName
int age
}
De waarde type moet beginnen met een alfabetisch teken en kan cijfers, streepjes, underscores, ronde haakjes en vierkante haken bevatten. De waarde name volgt een vergelijkbaar formaat als type, maar mag ook beginnen met een sterretje, als een andere optie om aan te geven dat het attribuut een primaire sleutel is. Verder zijn er geen andere beperkingen, en er is geen impliciete verzameling geldige gegevenstypen.
Entiteitsalias
Je kunt een alias aan een entiteit toevoegen met vierkante haken. Als een alias is opgegeven, wordt in het diagram de alias weergegeven in plaats van de entiteitsnaam; de alias volgt alle regels die ook voor de entiteitsnaam gelden.
Kopiëren
Insluiten
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
Attribuutsleutels en opmerkingen
Attributen kunnen ook sleutels of opmerkingen definiëren. Een sleutel kan een primaire sleutel (PK), vreemde sleutel (FK) of unieke sleutel (UK) zijn. Om meerdere sleutelbeperkingen op één attribuut op te geven, scheid je ze met komma's (bijvoorbeeld PK, FK). Opmerkingen worden gedefinieerd met dubbele aanhalingstekens aan het einde van het attribuut; in een opmerking mogen geen dubbele aanhalingstekens voorkomen.
Kopiëren
Insluiten
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
CAR {
string registrationNumber PK
string make
string model
string[] parts
}
PERSON ||--o{ NAMED-DRIVER : is
PERSON {
string driversLicense PK "The license #"
string(99) firstName "Only 99 characters are allowed"
string lastName
string phone UK
int age
}
NAMED-DRIVER {
string carRegistrationNumber PK, FK
string driverLicence PK, FK
}
MANUFACTURER ||--o{ CAR : makes
Richting
De richtingsverklaring declareert de richting van het diagram.
TB declareert de richting van het diagram van boven naar beneden; BT kan dit omkeren naar van beneden naar boven.
Kopiëren
Insluiten
erDiagram
direction TB
CUSTOMER ||--o{ ORDER : places
CUSTOMER {
string name
string custNumber
string sector
}
ORDER ||--|{ LINE-ITEM : contains
ORDER {
int orderNumber
string deliveryAddress
}
LINE-ITEM {
string productCode
int quantity
float pricePerUnit
}
LR declareert de richting van het diagram van links naar rechts; RL kan dit omkeren naar van rechts naar links.
Kopiëren
Insluiten
erDiagram
direction LR
CUSTOMER ||--o{ ORDER : places
CUSTOMER {
string name
string custNumber
string sector
}
ORDER ||--|{ LINE-ITEM : contains
ORDER {
int orderNumber
string deliveryAddress
}
LINE-ITEM {
string productCode
int quantity
float pricePerUnit
}
Knooppuntstijl instellen
Je kunt een specifieke stijl op een knooppunt toepassen, bijvoorbeeld een dikkere rand of een andere achtergrondkleur.
Kopiëren
Insluiten
erDiagram
id1||--||id2 : label
style id1 fill:pink,stroke:yellow,stroke-width:4px
style id2 fill:#69d,stroke:#f96,stroke-width:2px,color:#fff,stroke-dasharray: 5 5
Je kunt in één verklaring ook stijlen aan een lijst met knooppunten toevoegen:
Kopiëren
Insluiten
style nodeId1,nodeId2 styleList
Klasse
Handiger dan elke keer een stijl te definiëren is het definiëren van een stijlklasse en deze klasse toe te voegen aan knooppunten die er anders moeten uitzien.
Een klassendefinitie is zoals in het onderstaande voorbeeld:
Kopiëren
Insluiten
classDef className fill:pink,stroke:#333,stroke-width:4px
Je kunt ook meerdere klassen in één verklaring definiëren:
Kopiëren
Insluiten
classDef firstClassName,secondClassName font-size:12pt
De syntaxis voor het toevoegen van een klasse aan een knooppunt is als volgt:
Kopiëren
Insluiten
class nodeId1 className
Je kunt in één verklaring ook een klasse aan een lijst met knooppunten toevoegen:
Kopiëren
Insluiten
class nodeId1,nodeId2 className
Je kunt ook meerdere klassen tegelijk toevoegen:
Kopiëren
Insluiten
class nodeId1,nodeId2 className1,className2
Een eenvoudige manier om een klasse toe te voegen is de operator ::: om de klassenaam aan een knooppunt toe te voegen, zoals hieronder weergegeven:
Kopiëren
Insluiten
erDiagram
direction TB
CAR:::someclass {
string registrationNumber
string make
string model
}
PERSON:::someclass {
string firstName
string lastName
int age
}
HOUSE:::someclass
classDef someclass fill:#f96
Om relaties tussen entiteiten te declareren kun je de volgende syntaxis gebruiken:
Kopiëren
Insluiten
erDiagram
CAR {
string registrationNumber
string make
string model
}
PERSON {
string firstName
string lastName
int age
}
PERSON:::foo ||--|| CAR : owns
PERSON o{--|| HOUSE:::bar : has
classDef foo stroke:#f00
classDef bar stroke:#0f0
classDef foobar stroke:#00f
Net als bij de class-verklaring kan de verkorte syntaxis ook meerdere klassen tegelijk toepassen:
Kopiëren
Insluiten
nodeId:::className1,className2
Standaardklasse
Als een klasse default wordt genoemd, wordt deze toegewezen aan alle klassen zonder specifieke klassendefinitie.
Kopiëren
Insluiten
classDef default fill:pink,stroke:#333,stroke-width:4px;
Let op: aangepaste stijlen uit stijl- of andere class-verklaringen hebben voorrang en overschrijven de standaardstijl. (Bijvoorbeeld: de klasse default stelt voor een knooppunt een roze achtergrond in, maar als de klasse blue wordt toegepast, krijgt dat knooppunt een blauwe achtergrondkleur.)
Kopiëren
Insluiten
erDiagram
CAR {
string registrationNumber
string make
string model
}
PERSON {
string firstName
string lastName
int age
}
PERSON:::foo ||--|| CAR : owns
PERSON o{--|| HOUSE:::bar : has
classDef default fill:pink,stroke-width:4px
classDef foo stroke:#f90
classDef bar stroke:#ff0
classDef foobar stroke:#69f
Configuratie
Lay-out
De lay-out van het diagram wordt afgehandeld door render(); de standaardindeling is de ELK-lay-out, geschikt voor grotere en complexere diagrammen.
Om in plaats daarvan de klassieke Dagre-lay-out te gebruiken, kun je deze instellen in config in de YAML-frontmatter
Kopiëren
Insluiten
---
config:
layout: dagre
---
De Mermaid-code-inhoud is als volgt:
Kopiëren
Insluiten
---
title: Order example
config:
layout: elk
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses