ER图
<> 实体关系图(简称ER图)描述了特定知识字段中相互关联的感兴趣事物。一个基本的 ER图由实体类型(用于分类感兴趣的事物)组成,并且指定了实体(这些实体类型的实例)之间可以存在的关系,请注意,在ER图实际操作中,几乎总是将‘实体类型’简称为‘实体’。例如,’CUSTOMER 实体类型‘通常会直接称为‘CUSTOMER 实体’。这种做法非常普遍,因此不建议使用其他方式,但从技术上讲,实体是实体类型的抽象实例,ER图显示的正是这些抽象实例及它们之间的关系。这就是为什么实体总是使用单数名词命名的原因。 >
复制
嵌入
---
title: Order example
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
实体名称通常是大写的,尽管对此没有公认的标准,Mermaid 语法也没有强制要求。
实体之间的关系,用带有表示基数的端点标记的线表示。Mermaid 使用最流行的乌鸦脚符号,乌鸦脚直观地表示它所连接的实体可能有多个实例。
<> ER图可用于各种用途,从不包含任何实现细节的抽象逻辑模型,到关系数据库表的物理模型。在ER图上包含属性定义有助于理解实体的用途和含义,这些属性定义不必详尽无遗,通常一小部分属性就足够了。Mermaid允许以其类型和名称来定义它们。 >
复制
嵌入
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
}
在ER图上包含属性时,你必须决定是否将外键作为属性包含,这可能取决于你希望多大程度上表示关系表结构。如果你的图表是一个逻辑模型,并不打算暗示关系实现,那么最好不要包含这些属性,因为关联关系已经传达了实体之间的关联方式。例如,JSON数据结构可以在没有外键属性的情况下使用数组实现一对多关系。类似地,面向对象的编程语言可以使用指针或对集合的引用。即使对于那些旨在进行关系实现的模型,也可能认为包含外键属性会重复展示关系展示的信息,并且不会给实体增加意义。
语法
实体和关系
ER图的Mermaid语法与PlantUML兼容,并扩展了用于标记关系的功能。每个语句包括以下内容:
复制
嵌入
<first-entity> [<relationship> <second-entity> : <relationship-label>]
- first-entity 是第一个实体的名称。名称支持任何 Unicode 字符,如果用双引号括起来,则可以包含空格。
- relationship 描述了两个实体之间的相互关系。
- second-entity 是另一个实体的名称。
- relationship-label 描述了从第一个实体的角度来看关系。
例如:
复制
嵌入
PROPERTY ||--|{ ROOM : contains
该声明可以理解为:一个属性包含一个或多个房间,而一个房间只属于一个属性。这里的标签是从第一个实体的角度来看的:一个属性包含一个房间,但一个房间不包含属性。从第二个实体的角度来看,等效的标签通常很容易推断出来。
只有 first-entity 部分是强制性的。这使得显示没有关系的实体成为可能,这在迭代构建图表时非常有用。如果指定了语句的其他部分,则所有部分都是必填的。
Unicode 文本
实体名称、关系和属性都支持 unicode 文本。
复制
嵌入
erDiagram
"This ❤ Unicode"
关系语法
每个语句的 relationship 部分可以拆分为三个子部分:
- 第一个实体相对于第二个实体的基数
- 该关系是否赋予 '子' 实体身份'
- 第二个实体相对于第一个实体的基数
基数是一个属性,用来描述另一个实体可以与所涉及的实体相关联的元素数量。在上面的示例中,一个 PROPERTY 可以关联一个或多个 ROOM 实例,而一个 ROOM 只能关联一个 PROPERTY。每个基数标记中有两个字符,最外面的字符代表最大值,最里面的字符代表最小值。下表总结了基数的可能性:
| 值(左) | 值(右) | 意义 |
|---|---|---|
| |o | o| | 零或一 |
| || | || | 正好一个 |
| }o | o{ | 零个或多个(无上限) |
| }| | |{ | 一个或多个(无上限) |
| 值(左) | 值(右) | 意义 |
|---|---|---|
| one or zero | one or zero | 零或一 |
| zero or one | zero or one | 零或一 |
| one or more | one or more | 一个或多个 |
| one or many | one or many | 一个或多个 |
| many(1) | many(1) | 一个或多个 |
| 1+ | 1+ | 一个或多个 |
| zero or more | zero or more | 零个或多个 |
| zero or many | zero or many | 零个或多个 |
| many(0) | many(0) | 零个或多个 |
| 0+ | 0+ | 零个或多个 |
| only one | only one | 正好一个 |
| 1 | 1 | 正好一个 |
身份识别
关系可分为识别性和非识别性,分别用实线或虚线渲染。当其中一个实体无法在没有另一个实体的情况下独立存在时,这很重要。 例如,一家为人们驾驶汽车提供保险的公司可能需要存储 NAMED-DRIVER 的数据。在建模时,我们可能首先观察到,一个 CAR 可以由许多 PERSON 驾驶,而一个 PERSON 可以驾驶许多 CAR ,两者都可以在没有对方的情况下存在,因此这是一个非标识型关系,我们可以在 Mermaid 中指定为:PERSON }|..|{ CAR : "driver"。 请注意关系中间的两个点,这将导致在两个实体之间绘制虚线。但是,当这种多对多关系解析为两个一对多关系时,我们观察到如果没有 PERSON 和 CAR,NAMED-DRIVER 就不可能存在。这些关系变成了识别关系,并且会用连字符表示,对应的就是一条实线:
| 值 | 别名 |
|---|---|
| -- | 识别 |
| .. | 非识别 |
| 值 | 别名为 |
|---|---|
| to | 识别 |
| optionally to | 非识别 |
复制
嵌入
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
PERSON }o..o{ NAMED-DRIVER : is
复制
嵌入
erDiagram
CAR ||--o{ NAMED-DRIVER : allows
PERSON }o--o{ NAMED-DRIVER : is
属性
可以通过指定实体名称,然后跟随一个包含多个 type name 的块来为实体定义属性,其中块由一个大括号 {} 包围。属性会显示在实体框内,例如:
复制
嵌入
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
}
type 值必须以字母字符开头,并且可以包含数字、连字符、下划线、小括号和中括号。name 值遵循与 type 类似的格式,但也可以是星号开头,作为指示属性是主键的另一个选项。除此之外,没有其他限制,也没有隐含的有效数据类型集合。
实体别名
可以使用中括号为实体添加别名。如果提供了别名,图表中将显示别名而不是实体名称,别名遵循与实体名称相同的所有规则。
复制
嵌入
erDiagram
p[Person] {
string firstName
string lastName
}
a["Customer Account"] {
string email
}
p ||--o| a : has
属性键和注释
属性也可以定义键或注释。键可以是主键(PK)、外键(FK) 或唯一键(UK)。要在单个属性上指定多个键约束,用逗号分隔它们(例如,PK, FK)。注释通过属性末尾的双引号定义,注释中不能包含双引号字符。
复制
嵌入
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
方向
方向语句声明图表的方向。
TB 声明图表的方向是从上到下,BT 可以将其反转为从下到上。
复制
嵌入
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 声明图表的方向是从左到右,RL可以将其反转为从右到左。
复制
嵌入
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
}
设置节点样式
可以对节点应用特定样式,例如边框加粗或不同的背景色。
复制
嵌入
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
也可以在一个语句中将样式附加到节点列表:
复制
嵌入
style nodeId1,nodeId2 styleList
类
比每次定义样式更方便的是定义一个样式类,并将该类附加到需要不同外观的节点上。
类定义如下例所示:
复制
嵌入
classDef className fill:pink,stroke:#333,stroke-width:4px
也可以在一个语句中定义多个类:
复制
嵌入
classDef firstClassName,secondClassName font-size:12pt
将类附加到节点的语法如下:
复制
嵌入
class nodeId1 className
还可以在一条语句中将一个类附加到节点列表:
复制
嵌入
class nodeId1,nodeId2 className
也可以同时附加多个类:
复制
嵌入
class nodeId1,nodeId2 className1,className2
添加类的简便方式是使用运算符 ::: 将类名附加到节点,如下所示:
复制
嵌入
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
声明实体之间的关系可以使用以下语法:
复制
嵌入
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
类似于 class 语句,简写语法也可以一次应用多个类:
复制
嵌入
nodeId:::className1,className2
默认类
如果一个类被命名为 default,它将被分配给所有没有特定类定义的类。
复制
嵌入
classDef default fill:pink,stroke:#333,stroke-width:4px;
注意:来自样式或其他类语句的自定义样式具有优先权,并覆盖默认样式。(例如,default 类为节点设置粉色背景,但如果应用 blue 类,将为该节点提供蓝色背景颜色。)
复制
嵌入
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
配置
布局
图表的布局由 render() 处理,默认布局为 ELK 布局,适合较大且更复杂的图表。
要改用经典的 Dagre 布局,你可以在 YAML frontmatter 的 config 中设置它
复制
嵌入
---
config:
layout: dagre
---
Mermaid 代码内容如下:
复制
嵌入
---
title: Order example
config:
layout: elk
---
erDiagram
CUSTOMER ||--o{ ORDER : places
ORDER ||--|{ LINE-ITEM : contains
CUSTOMER }|..|{ DELIVERY-ADDRESS : uses