【データベーススペシャリスト試験】エンティティに付ける矢について

## この記事の趣旨

[データベーススペシャリスト試験](https://www.jitec.ipa.go.jp/1_11seido/db.html)に出題される基本的な問題の1つが、データベースの設計、すなわちER図を完成させる問題である

エンティティ同士を関係（リレーションシップ）を表す際のルールが決まっている

- ER図のエンティティにおいて、"多"側のエンティティに**矢**を付ける

この記事の趣旨は下記のとおり

- 矢をどこに付ければよいか、よく混乱する
- **混乱と向き合って、矢印の向きを腹落ちさせたい**

### リレーションシップにおける"矢"とは

IPAの過去問から一部キャプチャしたものを掲載する

> "1対多"のリレーションシップを表す線は、"多"側の端に矢を付ける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/00d13ff0-58ff-4399-9667-4d2ee49d5d39.png)
画像出典：[過去問題（問題冊子・配点割合・解答例・採点講評） - IPA](https://www.jitec.ipa.go.jp/1_04hanni_sukiru/_index_mondai.html)

### クラス図の矢／ER図の矢

普段はプログラムを書いているので、クラス図に慣れている

- オブジェクト指向で仕様を決めるとき・・**クラス図**

一方で、データベーススペシャリスト試験では、その名の通りデータベースを設計するためのER図が使われる

- データベースを設計するとき・・**ER図**

**クラス図とER図の比較をすることで、矢印混乱問題が解けるかもしれない**

## 実際の過去問をモデルケースに図を書く

[IPAの過去問](https://www.ap-siken.com/kakomon/17_aki/q65.html)を参考にモデル化してみる

注文、注文明細、商品の3つのエンティティの関係をクラス図／ER図／リレーションシップで表す

### クラス図

- 注文は注文明細を取りまとめる
- 注文明細は1つの商品の個数や小計を取りまとめる
- 商品は単独で存在できる

```plantuml
title クラス図

class 注文
{
    注文id
    ..
    顧客id
    List<注文明細>
    ..
    合計算出メソッド
}
note right: アプリケーションサービスに近い\nユースケースによって柔軟に変更し得る\n顧客オブジェクトなど種々のオブジェクトを組み合わせてユースケースを実現する

class 注文明細
{
    明細id
    ..
    商品id
    注文数
    ..
    小計
}

class 商品
{
    商品id
    ..
    商品名
    価格
}
note right: ドメイン寄りのオブジェクト\n不変であり、単独で存在し得る

注文 "1" *--> "多" 注文明細
注文明細  -->  商品
```

依存の矢印はよりドメイン寄り、ユーザーから遠い不変のものへ向いていくイメージ

### ER図／リレーションシップ

```plantuml
title ER図

entity 注文
{
    注文id [主キー]
    --
    顧客id [外部キー]
}

entity 注文明細
{
    明細id [主キー]
    --
    注文id [外部キー]
    商品id [外部キー]
}

entity 商品
{
    商品id [主キー]
}

注文 "1" ||--|{ "多" 注文明細
注文明細  }o--||  商品
```

これをリレーションシップで表すと、"多"側の端に矢を付けて下図のようになる

```plantuml
title リレーションシップ

entity 注文
{
    注文id [主キー]
    --
    顧客id [外部キー]
}

entity 注文明細
{
    明細id [主キー]
    --
    注文id [外部キー]
    商品id [外部キー]
}

entity 商品
{
    商品id [主キー]
}

注文 "1" --> "多" 注文明細
注文明細  "多" <-- "1" 商品
```

まさに過去問の答えのとおりのER図になる

### クラス図とリレーションシップの比較

比較のために、クラス図とリレーションシップを並べる

- 左のクラス図では、**注文明細から商品へ**矢印が向いている
- 右のリレーションシップでは、**商品から注文明細へ**矢印が向いている

この矢印の逆転が冒頭の混乱を招いている

```plantuml
title クラス図（左）／リレーションシップ（右）

class 注文
{
    注文id
    ..
    顧客id
    List<注文明細>
    ..
    合計算出メソッド
}

class 注文明細
{
    明細id
    ..
    商品id
    注文数
    ..
    小計
}
note left: 注文明細では商品の情報を使うので\n商品に向かって矢印が向いている

class 商品
{
    商品id
    ..
    商品名
    価格
}

注文 "1" *--> "多" 注文明細
注文明細  -->  商品

entity 注文_
{
    注文id [主キー]
    --
    顧客id [外部キー]
}

entity 注文明細_
{
    明細id [主キー]
    --
    注文id [外部キー]
    商品id [外部キー]
}
note right: "多"である注文明細に矢が付く

entity 商品_
{
    商品id [主キー]
}

注文_ "1" --> "多" 注文明細_
注文明細_  "多" <-- "1" 商品_
```

## 解決へ

ここからは混乱を解消するための話
自分を納得するためにいろいろと理由をこじつける

### 【検証1】クラス図とリレーションシップの共通点

先のクラス図とリレーションシップの関係を比較して気づいた点として
**注文と注文明細の関係性は、どちらも矢印の位置が同じであった**ということ

```plantuml
title クラス図（左）／リレーションシップ（右）

class 注文
{
    注文id
    ..
    顧客id
    List<注文明細>
    ..
    合計算出メソッド
}

class 注文明細
{
    明細id
    ..
    商品id
    注文数
    ..
    小計
}

注文 "1" *--> "多" 注文明細

entity 注文_
{
    注文id [主キー]
    --
    顧客id [外部キー]
}

entity 注文明細_
{
    明細id [主キー]
    --
    注文id [外部キー]
    商品id [外部キー]
}

注文_ "1" --> "多" 注文明細_
```

クラス図で`List<T>`に書き下しても不自然でない関係は、共通した矢印になる

※ 商品に注文明細履歴リストを付与することでも機能は実現できるかもしれないが、設計上不自然であるので却下される

（例）

全体|部分|部分が持つ外部キー
-|-|-
学校|List＜生徒＞|学校名
注文|List＜注文明細＞|注文番号
商品|List＜SKU＞|商品ID

### 【検証2】クラス図とリレーションシップの相違点

- **クラス図**
  - 明細は商品を参照したい、だから商品に向かって矢印を引いている
- **リレーショシップ**
  - 明細からみたら、商品は1つ
  - 商品からみたら、何度も注文されるので、明細は複数

この矢の矛盾をどう整理すべきか・・・

```plantuml
title クラス図（左）／リレーションシップ（右）

class 注文明細
{
    明細id
    ..
    商品id
    注文数
    ..
    小計
}

class 商品
{
    商品id
    ..
    商品名
    価格
}

注文明細  -->  商品

entity 注文明細_
{
    明細id [主キー]
    --
    注文id [外部キー]
    商品id [外部キー]
}

entity 商品_
{
    商品id [主キー]
}

注文明細_  "多" <-- "1" 商品_
```

#### ドメイン側が複数になる

顧客も加えてみた。

**顧客や商品などのドメインよりのオブジェクトは単数になる**と考えられる（かなり強引だが・・）

注文はユースケース寄りで、複数回実行される。動詞。

一方の顧客や商品は名詞であり、ユースケースに参照される側
この"参照"を頭に思い浮かべたときにクラス図よろしくドメイン側に矢を付けるのではなく、「いやいや今はER図の話だからその逆をいく」と考える

```plantuml
title リレーションシップ

entity 顧客 { }
note bottom: ドメインは単数！
entity 注文 { }
entity 注文明細 { }
entity 商品 { }
note bottom: ドメインは単数！

顧客 -> 注文
注文 -> 注文明細
注文明細 <- 商品
```

```plantuml
title クラス図

class 顧客 { }
class 注文 { }
class 注文明細 { }
class 商品 { }

顧客 <- 注文
注文 *-> 注文明細
注文明細 -> 商品
```

#### 顧客と注文はリストで表せる

顧客は注文履歴をListで持っていても不自然ではないので
その考えであればリレーションシップと矢の位置が一致する

```plantuml
title クラス図

class 顧客
{
    注文履歴 List＜注文＞
}
class 注文 { }
class 注文明細 { }
class 商品 { }

顧客 o-> 注文
注文 *-> 注文明細
注文明細 -> 商品
```

### 【検証3】記法の違い

多重度を表す記法には、鳥の足のようなIE記法と、丸印のIDEF1X記法があるらしい[^2]
[^2]:[若手プログラマー必読！５分で理解できるER図の書き方５ステップ](https://it-koala.com/entity-relationship-diagram-1897)

どちらも多重度が"多"の方になんらかの印がつく（鳥の足or丸印）

リレーションシップに用いられる矢印も同じで、"多"の方に付けられる

すなわち、**矢印を矢印と思わず**、なんらかの印と思うことで
**なんらかの印は常に"多"につく**と思い込めばいい

さらには、**なんらかの印がついた方には、もう片方への外部キーが存在する**、とまで思い込んでしまってよいかもしれない

そもそも**多いものは繰り返しを生じさせて正規化を妨げるから外に追いやられた**のであり、追いやられた側は**元居た場所への参照＝外部キー**がないと生きていけないのだから。。。

> E-R図においてエンティティ間の多重度が"1対多"であるとき、それを関係データベースに変換すると、"1"側のエンティティが主キー属性を持つ表、"多"側のエンティティが外部キーを持つ表になります。
> 引用元：[データベーススペシャリスト平成28年春期 午前Ⅱ 問6](https://www.db-siken.com/kakomon/28_haru/am2_6.html)

## まとめ

- クラス図において`List<T>`で表すことができるなら、リスト化されるほうに矢をつける
- `List<T>`で表すと不自然な場合（商品と注文明細）、ドメイン側は単数になる。すなわちドメインと逆側に矢がつく
- 印がついた側のエンティティには単数側への外部キーをもつ

## 参考

- [PlantUML で ER 図（ERD）を描く（似非ではないです）](https://qiita.com/Tachy_Pochy/items/752ef6e3d38e970378f0)
- [【コードで分かるUMLシリーズ】クラス図の書きかた（集約とコンポジションの意味の違い）](https://qiita.com/azuki8/items/49e1add6ea838cd13734)