laravel

Laravel8で外部キー制約をマイグレーションで追加する方法【デフォルトの型に注意】

鍵

 

あなた
Laravel8で外部キー制約をマイグレーションで設定するにはどうしたらいいですか?

 

今回はこんな疑問に答えていきます。

 

【前提】

・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の記事はこちらから見ることができます。

 

-laravel

© 2021 エンジニアてんし君ブログ