LoginSignup
6
8

More than 1 year has passed since last update.

Laravelのdb:seedで1452エラーが出る

Last updated at Posted at 2019-06-25

Laravelを触り始めて約一ヶ月の初心者です
つまづいたのでメモ

結論としてはLaravelクエリビルダのdelete(というかMySQLのDELETE)ではauto_incrementがリセットされないという仕様が分かってなかったっていう話です

環境

Laravel 5.8


1つのUserに対して多数のItemが紐付く構造
userを削除した際はitemも削除するよう外部キーを持たせてあります

2019_06_25_000000_create_item_table.php
public function up()
    {
        Schema::create('items', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->text('title');
            $table->bigInteger('user_id')->unsigned();
            $table->timestamps();

            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');
        });
    }

ユーザテーブルのマイグレーションファイルはLaravelデフォルトなので省略

↓こちらがseeder

UserTableSeeder.php
public function run()
    {
        DB::table('users')->delete();

        App\User::create([
            'name'     => 'hoge',
            'email'    => 'hoge@example.com',
            'password' => Hash::make('hogehoge'),
        ]);
        App\User::create([
            'name'     => 'hage',
            'email'    => 'hage@example.com',
            'password' => Hash::make('hagehage'),
        ]);
    }
ItemTableSeeder.php
public function run()
    {
        DB::table('items')->delete();

        App\Item::create([
            'title'   => '君という花',
            'user_id' => '1',
        ]);
        App\Item::create([
            'title'   => 'リライト',
            'user_id' => '2',
        ]);
    }

2つともseed時は一回deleteで全消ししてからデータを挿入します

一回migrate:refreshを挟まないとdb:seed出来ない問題

refreshせずにシーディングを実行すると1452エラーが出る

$ php artisan db:seed
Seeding: UsersTableSeeder
Seeding: ItemsTableSeeder

   Illuminate\Database\QueryException  : SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails

refreshを挟むと何故か成功する

php artisan migrate:refreshしたあとにphp artisan db:seedを再度実行

$ php artisan migrate:refresh                                                                                         
Rolling back: 2019_06_10_190034_create_items_table
Rolled back:  2019_06_10_190034_create_items_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
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: 2019_06_10_190034_create_items_table
Migrated:  2019_06_10_190034_create_items_table
$ php artisan db:seed                                                                                                 [~/dev/app/gaogao_gate/likes]
Seeding: UsersTableSeeder
Seeding: ItemsTableSeeder
Database seeding completed successfully.

(逆に)なんでや…

再度db:seedを実行、やっぱり1452のエラーが出る…
UserTableを確認してみた

mysql> select id from users;
+----+
| id |
+----+
|  3 |
|  4 |
+----+
2 rows in set (0.01 sec)

id途中から始まってるやんけ!

どうやらdeleteではauto_incrementに設定したidがリセットされない様子
既に存在しない親のidをitemに与えようとして1452エラーが出ていたようです

どうしよう

公式ドキュメント見てdeleteじゃなくてtruncate使えばええやん!と思ったけどそうでも無い様子 (1701エラーが出る)
外部キーがあると使えない模様…(rollbackもできなくなる)

deleteと同時にauto_incrementを1に戻してしまえばよい

そんな都合のいいクエリは無いみたいなのでdeleteの下にSQLを1行追加

UserTableSeeder.php
DB::table('users')->delete();
DB::unprepared("ALTER TABLE users AUTO_INCREMENT = 1 ");

これでとりあえず(ゴリ押し)解決したみたいです👏

ていうかItemSeederで親のidを数字で与えているのがそもそもダメなのでは…

テストデータだから許して

追記

以下、真偽不明になる事案があったため気にしないでください(検証すればええやんって話ですが…)
user_idが途中から始まるのは明示的に指定しなかった場合に起きる模様、なので

UserTableSeeder.php
public function run()
    {
        DB::table('users')->delete();

        App\User::create([
            'id'       => '1',
            'name'     => 'hoge',
            'email'    => 'hoge@example.com',
            'password' => Hash::make('hogehoge'),
        ]);
        App\User::create([
            'id'       => '2',
            'name'     => 'hage',
            'email'    => 'hage@example.com',
            'password' => Hash::make('hagehage'),
        ]);
    }

のように明示的にidを指定するとAUTO_INCREMENTSを無視できるみたいです

6
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
8