リレーションと外部キー
以前、リレーションの作業を行なった。
【Laravel入門】リレーションとユーザーの一覧表示
そして、動作確認のためユーザーの削除を行ってみたが、予想と違う結果となった。自分の予想ではこうなるはずだったのに・・・
「ユーザーが削除されると、自動的にそのユーザーの投稿記事が削除される。」
しかし、削除されたユーザーに紐づく投稿記事が消えない。これは外部キーの設定を忘れていたためだった。ちなみに、自分の持つ外部キー関連の概念はこんなところだ。
- ユーザーが保管されている
usersテーブルと投稿記事が保管されているarticlesテーブルは、1対多の関係にある。 - articlesテーブルは
user_idを元にusersテーブルから記事の作成者情報を得ている。この状態は、articlesテーブルが従テーブル、usersテーブルが主テーブルだと言える。 - 従テーブルで主テーブルを参照するために使われるキーを
外部キーと呼ぶ。
今回はその設定を行うことにした。
外部キー用のマイグレーションファイルを作成
上記の設定を行うためには、user_idを外部キーに設定しなければならない。
既存のcreate_articles_tableにその設定を書き加えて行く方法もあるらしいが、user_idは他のカラムと役割が違う。(それに記述が上手く出来ず、何回か失敗した;)
そのため、user_idの設定は独立したマイグレーションファイルadd_user_id_articles_tableに記述することにした。
create_articles_tableの編集
user_idを専用ファイルで作成するため、create_articles_tableから$table->integer('user_id');を削除した。
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateArticlesTable extends Migration
{
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
// $table->integer('user_id');を削除
$table->string('title');
$table->string('content');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('articles');
}
}
add_user_id_articles_tableの作成
add_user_id_articles_tableを新たに作成し、編集する。
$ php artisan make:migration add_user_id_articles_table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddUserIdArticlesTable extends Migration
{
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->foreign('user_id')
->references('id')->on('users')
->onDelete('cascade');
});
}
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropForeign('articles_user_id_foreign');
});
}
}
内容を説明する。
up関数
-
Schemaファサードのtableメソッドを使用する。 - tableメソッドは第1引数に
テーブル名、第2引数にBlueprintインスタンスの$tableを指定する。 -
$tableのintegerメソッドでuser_idを作成し、カラム修飾子unsignedメソッドを実行する。 -
unsignedメソッドはMySQLで整数カラムを符号なしに設定する。これを実行しないとエラーが発生するので注意すること。 -
foreignメソッドでuser_idを外部キーに設定する。 -
referencesメソッドで、従テーブルのuser_idと紐付いている主テーブルのidを指定する。 -
onメソッドで主テーブルusersを指定する。 -
onDeleteメソッドでuserが削除・更新された場合の処理を記述する。今回、引数はcascadeを指定する。
onDeleteメソッドには、以下4種類の引数がある。
- cascade
- set null
- no action
- restrict
詳細はこちらのサイト様から。
Laravel 5.3 Eloquent ORM 入門 2 (マイグレーション)
down関数
- 外部キーを削除するためには
dropForeignメソッドを使用する。 - dropForeignメソッドの引数は、命名規則により
テーブル名_外部キー名_foreignとなる。
動作確認
tableメソッドをcreateメソッドと間違えたり、unsigned()を記述し忘れたり、途中でエラーの連続だった。
$ php artisan migrate:refresh
Rolling back: 2018_05_03_141933_create_articles_table
Rolled back: 2018_05_03_141933_create_articles_table
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back: 2014_10_12_100000_create_password_resets_table
Rolling back: 2014_10_12_000000_create_users_table
Rolled back: 2014_10_12_000000_create_users_table
In Connection.php line 664:
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id' (SQL: alter table `a
rticles` add `user_id` int not null)
In Connection.php line 458:
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'user_id'
何とかマイグレーションファイルを正しく編集し、migrationを実行できた。以下のコマンドでは、テーブルが存在しないのにrefreshしているため、最初にMigration table not found.と怒られている;
$ php artisan migrate:refresh
Migration table not found.
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table
Migrating: 2018_05_03_141933_create_articles_table
Migrated: 2018_05_03_141933_create_articles_table
Migrating: 2018_05_16_185519_add_user_id_articles_table
Migrated: 2018_05_16_185519_add_user_id_articles_table
これで、ユーザーを削除すると、そのユーザーに紐づく投稿記事も削除されるようになった。
今回はここまで。