状況
Laravelでmigrationファイルを作成、カラムの追加、外部キーを設定してmigrationしようとすると外部キーの設定が上手くいかなかった。
usersテーブルのidをexpensesテーブルuser_idを、categoryテーブルのidがexpensesテーブルのcategoy_idが参照するうに設定したかったが、user_idの方だけ失敗した。
因みにusersテーブルはphp artisan ui react --authでログイン/ユーザー登録スカフォールド(React)を生成した時に自動的に作成されたテーブル。
試したこと
categoryテーブルのidはincrementsで定義しているため、型がunsignedになるので注意と書いてあったのでexpensesテーブルのcategory_idはunsignedを明示的に定義した。こっちは上手くいった。
初回のmigrationでは以下のファイルを使いました。
//これは自動的に作成されたファイル。何もいじってない。
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
//idをIncrementsで定義
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
}
public function up()
{
Schema::create('expenses', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->integer('price');
//unsignedIntegerで定義して外部キーを設定
$table->unsignedinteger('category_id');
$table->foreign('category_id')->references('id')->on('categories');
//Integerで定義して外部キーを設定
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
こんな感じのテーブルができてました。
//usersテーブル
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| email | varchar(255) | NO | UNI | NULL | |
| email_verified_at | timestamp | YES | | NULL | |
| password | varchar(255) | NO | | NULL | |
| remember_token | varchar(100) | YES | | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------------+---------------------+------+-----+---------+----------------+
//categoryテーブル
+-------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
+-------+------------------+------+-----+---------+----------------+
//expensesテーブル
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| price | int(11) | NO | | NULL | |
| category_id | int(20) unsigned | NO | | NULL | |
| user_id | int(20) | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
原因と対処法
usersテーブルでidは$table->id();で定義されているためデータ型は「bigint(20) unsigned」になっていたためexpensesテーブルのusers_idのデータ型(int(20)と不一致が起きてしまっていた。
修正後
public function up()
{
Schema::create('expenses', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->integer('price');
$table->unsignedinteger('category_id');
$table->foreign('category_id')->references('id')->on('categories');
//unsignedBigintegerに変更
$table->unsignedBiginteger('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
}
データ型もしっかり合っています。
usersテーブル
+-------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+---------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| price | int(11) | NO | | NULL | |
| category_id | int(10) unsigned | NO | MUL | NULL | |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------+---------------------+------+-----+---------+----------------+
ちゃんと外部キーの設定もできました。
mysql > show create table expenses;
| expenses | CREATE TABLE `expenses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`price` int(11) NOT NULL,
`category_id` int(10) unsigned NOT NULL,
`user_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `expenses_category_id_foreign` (`category_id`),
KEY `expenses_user_id_foreign` (`user_id`),
CONSTRAINT `expenses_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`),
CONSTRAINT `expenses_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |