はじめに
Laravelを使ってアプリ開発を進める中で、避けて通れないのがテーブル設計と リレーション(関連) の考え方。
その中でも「外部キー制約(foreign key)」は、データの整合性を保つためにとても重要です。
この記事では、外部キー制約の基本や、Laravelでの実装方法を自分用の備忘録としてまとめます。
①外部キー制約とは?
外部キーとは、あるテーブルのカラムが、別のテーブルの主キーとつながっている関係性のこと。
例:
-
posts
テーブルのuser_id
は、users
テーブルのid
を参照する
このような関係を定義することで、間違ったデータが登録されるのを防げるようになります。
②Laravelでの外部キー制約の書き方
基本構文(Laravel 7以降推奨)
$table->foreignId('user_id')->constrained();
これで以下のような制約が自動で付加されます。
- user_id は unsignedBigInteger 型になる
- 参照先は users.id
- 外部キー制約が自動的に張られる
③もっと詳しく指定したい場合
$table->foreignId('category_id')
->constrained('categories')
->onDelete('cascade');
④よく使うオプション
⑤具体例:postsテーブルでの外部キー設定
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
このようにすることで
- user_id に存在しない users.id は登録できなくなる
- 親ユーザーが削除されると、その人の投稿も削除される
補足:本当に onDelete('cascade')
でいいのか?
実務で多くのデータを扱うようになると、「親データを消したら自動で子も削除される」という cascade
の動きが、想定外のデータ消失を引き起こすリスクになることがあります。
例えば、「退会したユーザーの投稿は残しておきたい」といったケースでは、SET NULL
や RESTRICT
を使う方が適しています。
よく使うオプション比較
オプション | 動作 | 主な用途 |
---|---|---|
cascade |
親を削除すると子も削除 | テストデータ、一時的な関係 |
set null |
子の外部キーを null にする | 履歴データを残したい場合 |
restrict |
子が残っていたら削除できない | データ保全が最優先の場面 |
書き方の例:
$table->foreignId('user_id')
->nullable()
->constrained()
->onDelete('set null');
※ set null を使うときは nullable() を忘れずに!
$table->foreignId('user_id')
->constrained()
->onDelete('restrict');
経験からの教訓:
- cascade を安易に使うと、意図しない大量削除の原因になる
- 削除連鎖は便利だけど、明示的に「削除する責任」をコードで持つ設計の方が安全
- set null や restrict を使う習慣を身に付けておくと、設計力が一段上がる
⑥よくあるエラー:外部キー制約違反
例)「Integrity constraint violation」エラー
このエラーは、以下のような状況で発生します
- posts.user_id = 3 に対して、users.id = 3 が存在しない
- 親を削除しようとしても、まだ子テーブルにデータが残っている
対策:
- onDelete('cascade') などの設定を見直す
- データの削除順序を調整する(子→親)
⑦外部キー制約を使うメリット
⑧まとめ
- 外部キー制約は、 データベース設計における「交通ルール」 のようなもの
- Laravelでは foreignId()->constrained() を使えば簡単に設定できる
- 実務でも、データの整合性を保つために積極的に活用したい