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


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

結論としては[Laravelクエリビルダ](https://readouble.com/laravel/5.8/ja/queries.html)のdelete(というかMySQLのDELETE)では**auto_incrementがリセットされない**という仕様が分かってなかったっていう話です

## 環境
Laravel 5.8

----

１つの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エラーが出ていたようです

## どうしよう
[公式ドキュメント](https://readouble.com/laravel/5.8/ja/queries.html)見て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`を無視できるみたいです~~