流程類
圖形化表達方式
思維類
結構化表達方式
筆記類
高效化表達方式

ER圖語法

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