今回はこんな疑問に答えていきます。
【前提】
・laravel8系
・マイグレーションの仕組み自体は把握している(把握できていない方はLaravel8でマイグレーションを行う方法【カラム追加/削除・カラム変更・インデックス追加/削除など】を読んで学習しておきましょう)
Laravel8で外部キー制約をマイグレーションで追加する方法
結論から話すと、Laravel8で外部キー制約をマイグレーションで設定する方法は以下の2つになります。
・パターン1:foreign、references、onメソッドを使う
・パターン2:foreignId、constrainedメソッドを使う
パターン1は旧式で、パターン2はLaravel7から使えるようになったようですね。
それぞれについて解説します。
パターン①
パターン1の場合の記述は以下のようになります。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
//user_idはuserテーブルのidを外部キーとする
$table->foreign('user_id')->references('id')->on('users');
});
パターン1は少し冗長ではありますね。
そこでパターン2が出てきました。
パターン②
パターン2では以下のように記述できます。
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('posts', function (Blueprint $table) {
//user_idはuserテーブルのidを外部キーとする
$table->foreignId('user_id')->constrained();
});
1行で完結して、見やすくなりました。
laravel7以降使えるようです。
「Referencing column '〇_id' and referenced column 'id' in foreign key constraint '〇〇' are incompatible.」というエラーが出る場合
ちなみになのですが、「Referencing column '○_id' and referenced column 'id' in foreign key constraint '〇〇' are incompatible.」のようなエラーが出るときがあります。
このエラーが出るときは「外部キーを設定しようとしたカラムの型が、間違っている」ということが考えられます。
例えば、usersテーブルのidはtinyintなのに、postsテーブルの user_idでbigintを指定してしまったとかです。
注意:デフォルトのforeignIdはbigIntegerを指定する
注意点なのですが、foreignIdメソッドを使った場合はデフォルトでbigIntegerが指定されます。
呼び出し先のメソッドは以下のようになっています。
public function foreignId($column)
{
return $this->addColumnDefinition(new ForeignIdColumnDefinition($this, [
'type' => 'bigInteger',
'name' => $column,
'autoIncrement' => false,
'unsigned' => true,
]));
}
つまり、外部キーとしてbigInteger以外の型を指定したい場合はforeignIdを使わないほうがいいということです。
Laravel8で型指定で外部キー制約を付けたい場合
Laravel8で型指定で外部キー制約を付けたい場合は、foreignIdを使わない書き方をしましょう。
2つほど例を書いておきます。
以前の書き方
旧式の書き方であれば、「カラム作成」「外部キー設定」が別に書かれていました。
なので、柔軟に型を変更可能です。
//型を自在に変更できる
$table->unsignedTinyInteger('user_id');
//型指定後に外部キー設定
$table->foreign('user_id')->references('id')->on('users');
特に問題なければ上記やり方がスマートです。
DBファサードを使ってSQL直書き
DBファサードを使ってSQLを直書きして、外部キーを設定する方法もあります。
コードは次のような感じになります。
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
class AddForeignKeyToMessages extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('messages', function (Blueprint $table) {
DB::statement('ALTER TABLE `laravel`.`messages`
ADD INDEX `messages_user_id_foreign_idx` (`user_id` ASC) VISIBLE;');
DB::statement('ALTER TABLE `laravel`.`messages`
ADD CONSTRAINT `messages_user_id_foreign`
FOREIGN KEY (`user_id`)
REFERENCES `laravel`.`users` (`id`)
ON DELETE RESTRICT
ON UPDATE RESTRICT;');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('messages', function (Blueprint $table) {
DB::statement('ALTER TABLE `laravel`.`messages`
DROP FOREIGN KEY `messages_user_id_foreign`;');
DB::statement('ALTER TABLE `laravel`.`messages`
DROP INDEX `messages_user_id_foreign`;');
});
}
}
ただ、さすがに冗長すぎるので、優先して使うことはないかなと。
SQL直書きは、便利ですが、見やすさを失うこともあるので、適時に使っていきましょう。
今回は以上です。
Laravelの記事はこちらから見ることができます。