リレーションと外部キー
以前、リレーションの作業を行なった。
【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
これで、ユーザーを削除すると、そのユーザーに紐づく投稿記事も削除されるようになった。
今回はここまで。