こんにちは!
今回はLaravelでの「外部キー制約の付け方」というテーマで書いていきます。
「外部キー制約」という言葉を聞いたことがあるでしょうか?外部キー制約をしっかり使うと、データの整合性が保たれて、システム全体が安定します。逆にこれを忘れると、データの不整合が起きたり、バグに繋がることも…。
本記事では、外部キー制約の基本から、Laravelでどのように設定するかまでをわかりやすく解説していきます!

「そもそも外部キー制約って何?」
「Laravelで外部キー制約をつける方法は?」
このような疑問を持っている方は参考になるかと思います。
それでは、早速みていきましょう!
そもそも外部キー制約って?
そもそも外部キー制約ってなに?と思われる方もいるかもしれないので、軽く触れておきます。
外部キー制約は、簡単に言うと、「このデータは他のテーブルにあるデータと関連してますよ」というルールをデータベースに教えてあげるものです。
例えば、「注文テーブル」と「ユーザーテーブル」があったとします。各注文には「この注文はどのユーザーがしたのか」という情報が必要です。ここで、外部キー制約が登場します。注文テーブルに「user_id」っていう列を作って、それをユーザーテーブルのIDと結びつけて「この注文はちゃんと存在するユーザーがしたものだよ」というルールを作ります。
もし、間違って存在しないユーザーのIDを入れようとしたら、外部キー制約が「ちょっと待って、そのユーザーは存在しないよ」というのを教えてくれるので、矛盾したデータが入るのを防いでくれます。
こんな感じで、外部キー制約はデータ同士の関係性を保つ大事な役割をしてくれています。
Laravelでの外部キー制約の基本
本記事では、Laravel11系を前提として解説していきます。
仮に、postsテーブルにuser_idという、usersテーブルへの外部キーがあることを想定してみます。この場合、postsテーブルのマイグレーションファイルは次のようになります。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
});以下の行で、外部キー制約をつけています。
$table->foreign('user_id')->references('id')->on('users');foreignには外部キーを指定し、referencesにはリレーション先のテーブルの参照カラムを設定します。最後に、onメソッドでリレーション先のテーブルを指定すれば外部キー制約をつけることができます。
実際に外部キー制約をつけてみる
それでは、実際に外部キー制約をつけみましょう。
$ php aritisan migratephpMyAdminを見てみると、postsテーブルの外部キーであるuser_idに鍵マークが付与されていることが確認できます。

これで外部キー制約を設定することができました。
もっとシンプルな書き方
ただし、この書き方は少々冗長なので、以下のようにもっとシンプルに書くことができます。
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained();
});ただ、この書き方は少し注意が必要です。この書き方だと、リレーション先のテーブルや参照カラムを指定していませんよね。なので、Laravel側で外部キー名が「user_id」ということは、リレーション先のテーブル名はusersテーブルで、参照カラムはidなのだろうと予測して勝手に判断します。
例えば、参照カラムがidではなく別のカラム名だったりする場合には別途指定する必要があります。
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained(
table: 'テーブル名', indexName: 'インデックス名'
);
});ここだけ注意しておきましょう。
カスケード設定
カスケード設定も重要です。カスケード設定を行うことで、親テーブルが削除されたり更新されたりすると、子テーブルも自動的に削除したり更新したりすることができます。
これに関しては、説明するよりも実際に挙動をみた方が早いです。例えば、以下のような2つのテーブルがあったとします。
usersテーブル
| id | name | password | |
| 1 | test | test@example.com | test@1234 |
| 2 | test2 | test2@example.com | test2@1234 |
postsテーブル
| id | user_id | title | body |
| 1 | 1 | 1投稿目! | 初投稿です! |
| 2 | 2 | 2投稿目! | 2回目の投稿です! |
postsテーブルのuser_idという外部キーには、更新カスケードと削除カスケードが設定されているものとします。
カスケードには更新カスケードと削除カスケードがあります。それぞれ見てみます。
更新カスケード
例えば、1番目のユーザーIDを1から3に更新してみます。
$ php artisan tinker
> use App\Models\User;
> $user = User::find(1);
> $user->id = 3;
> $user->save(); // IDを3に更新!この状態でデータベースを覗いてみます。


usersテーブルのIDが更新されているのは普通ですが、それと同時にpostsテーブルのuser_idも自動的に3に更新されています!
このように、親テーブルのIDが更新されると、子テーブルの外部キーも自動的に更新されるようになります。これにより、データの矛盾を防ぐことができるわけですね。
削除カスケード
それでは次に、1番目のユーザーを削除してみます。
$ php artisan tinker
> $user = User::find(1);
> $user->delete();それでは、データベースを覗いてみましょう。


ユーザーID1のユーザーが削除されると同時に、postsテーブルのユーザーIDが1のレコードも自動的に削除されています!
今回はこれで以上になります。
最後までご清聴ありがとうございました!


コメント