エンティティを洗い出す
設計の最初のステップは「何のデータを管理するか」を明確にすることです。このステップで洗い出すのがエンティティです。エンティティの粒度や属性の決め方が、その後の設計全体の品質を左右します。
エンティティとは
エンティティ? データベースで管理する「もの」や「概念」。ユーザー・商品・注文などがエンティティの例。ER図ではテーブルとして表現される。 とは、現実世界の「もの」や「こと」をデータとして表現したものです。データベースでは通常、1つのエンティティが1つの テーブル? データベース内のデータの入れ物。Excelのシートのように行と列でデータを管理する。 に対応します。
エンティティの特徴は次のとおりです。
- 識別可能 — 個々のインスタンスを区別できる(注文Aと注文Bは別もの)
- 属性を持つ — エンティティの特性を表すデータ項目がある
- 他のエンティティと関係がある — ユーザーは注文を持つ、など
よく混乱するのが「エンティティ」と「属性」の区別です。例えば「住所」は、単純なシステムではユーザーの属性(カラム)でよいですが、複数の配送先を管理したいなら「住所」を独立したエンティティにすべきです。判断基準は「それ単独で管理する必要があるか」です。
ECサイトのエンティティを洗い出す
ECサイトの要件を考えてみましょう。
ユーザーが商品を検索して購入できる。商品はカテゴリで分類される。購入履歴を確認できる。商品にレビューを書ける。
この要件から、次のエンティティが見えてきます。
| エンティティ | 説明 |
|---|---|
| ユーザー (users) | サービスの会員 |
| 商品 (products) | 販売する商品 |
| カテゴリ (categories) | 商品の分類 |
| 注文 (orders) | ユーザーが行った購入 |
| 注文明細 (order_items) | 注文に含まれる各商品と数量 |
| カート (carts) | 購入前の一時的な商品リスト |
| レビュー (reviews) | 商品に対するユーザーの評価 |
「注文明細」が独立したエンティティになっている点に注目してください。1つの注文に複数の商品が含まれるため、注文と商品の関係を表す中間的なエンティティが必要です。
属性(カラム)を決める
エンティティが決まったら、それぞれの属性を決めます。
users テーブル
users
- id BIGINT UNSIGNED AUTO_INCREMENT -- 主キー
- name VARCHAR(100) NOT NULL -- 氏名
- email VARCHAR(255) NOT NULL UNIQUE -- メールアドレス
- password VARCHAR(255) NOT NULL -- ハッシュ済みパスワード
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
products テーブル
products
- id BIGINT UNSIGNED AUTO_INCREMENT
- category_id BIGINT UNSIGNED NOT NULL -- カテゴリへの外部キー
- name VARCHAR(255) NOT NULL
- description TEXT
- price INT UNSIGNED NOT NULL -- 円単位で整数管理
- stock INT UNSIGNED NOT NULL DEFAULT 0
- created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
属性を決めるときのポイントをいくつか挙げます。
- 金額は整数で — 浮動小数点(FLOAT, DOUBLE)は丸め誤差が出るため、円単位なら INT、銭単位なら DECIMAL を使います
- NULL を安易に許可しない — NULL は「値が不明」を意味し、扱いが複雑になります。できるだけ NOT NULL にしましょう
created_at/updated_atは必ず入れる — いつ作成・更新されたかのトレースは後々必ず役に立ちます
主キーの選び方
主キー? テーブルの各行を一意に識別するためのカラム。通常は自動で採番される`id`が使われる。 は各レコードを一意に識別するためのカラムです。選択肢は大きく2つあります。
代理キー(Surrogate Key)
システムが自動的に割り当てる意味のない連番や UUID です。
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY
-- または
id CHAR(36) DEFAULT (UUID()) PRIMARY KEY
メリット:
- 設計がシンプル
- 値が変わらない(メールアドレスが変わっても主キーに影響しない)
- 外部キーとして参照しやすい
自然キー(Natural Key)
現実世界のデータをそのまま主キーにする方法です(メールアドレス、ISBN コードなど)。
email VARCHAR(255) PRIMARY KEY
デメリット:
- 値が変わる可能性がある
- 文字列型は連番に比べてインデックスが大きくなる
- 外部キーとして参照すると結合クエリが重くなる
結論として、ほとんどのケースでは代理キー(id BIGINT AUTO_INCREMENT)を推奨します。
エンティティ候補の見極め方
洗い出したエンティティ候補が本当にエンティティとすべきか、属性にすべきかを判断する基準を整理します。
独立したエンティティにすべきケース:
- 複数の値を持つ可能性がある(ユーザーが複数の住所を持てる)
- それ自体に複数の属性がある(住所なら都道府県・市区町村・番地が必要)
- 他のエンティティとも関係を持つ(配送先住所は注文からも参照される)
属性(カラム)のままでよいケース:
- 常に1つの値しか持たない
- 属性が1つか2つしかない
- 他から参照されることがない
例えば「性別」は属性(カラム)で十分ですが、「タグ」は複数付与できるので独立したエンティティにする必要があります。
まとめ
エンティティの洗い出しは設計の根幹です。後から「このエンティティが足りなかった」となると、大きな改修が必要になります。要件を丁寧に読み込み、「管理が必要なもの・ことはすべて拾えているか」を確認しましょう。
次回は、洗い出したエンティティのデータを整理するための正規化を学びます。