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"
關係語法
每個陳述式的關係部分可以拆分為三個子部分:
- 第一個實體相對於第二個實體的基數
- 該關係是否賦予子實體身分識別
- 第二個實體相對於第一個實體的基數
基數是一個屬性,用來描述另一個實體可以與所涉及的實體相關聯的元素數量。在上面的範例中,一個 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