【问题标题】:Laravel 5.1 Migration and Seeding Cannot truncate a table referenced in a foreign key constraintLaravel 5.1 迁移和播种无法截断外键约束中引用的表
【发布时间】:2015-09-20 10:24:24
【问题描述】:

我正在尝试运行迁移(见下文)并为数据库播种,但是当我运行时

php artisan migrate --seed

我收到此错误:

Migration table created successfully.
Migrated: 2015_06_17_100000_create_users_table
Migrated: 2015_06_17_200000_create_password_resets_table
Migrated: 2015_06_17_300000_create_vehicles_table

[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot truncate a table
referenced in a foreign key constraint (`app`.`vehicles`, CONSTRAINT `vehic
les_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `app`.`users` (`id`
)) (SQL: truncate `users`)

[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot truncate a table
referenced in a foreign key constraint (`app`.`vehicles`, CONSTRAINT `vehic
les_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `app`.`users` (`id`
))

我查了一下这个错误应该是什么意思,还发现examples的其他人遇到了同样的问题,甚至只是与使用MySQL有关,以及他们的解决方案,但应用:

DB::statement('SET FOREIGN_KEY_CHECKS=0;'); and 
DB::statement('SET FOREIGN_KEY_CHECKS=1;'); 

在 down() 内似乎不起作用,当我在 MySQL 中运行 describe 时,表看起来正确。

正确命名迁移以确保首先迁移用户表,然后迁移车辆,以便可以应用外键,并且正确设置的表表明迁移已运行,但随后发生错误。我删除并重新创建了数据库并再次尝试,结果相同。我也不明白为什么它试图在数据库的第一次迁移和种子时截断,我不会想到当你尝试运行 php artisan migrate:refresh --seed 时会发生这种情况。

// 2015_06_17_100000_create_users_table.php

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('username', 60)->unique();
            $table->string('email', 200)->unique();
            $table->string('password', 255);
            $table->string('role')->default('user');
            $table->rememberToken();
            $table->timestamps();
        });
    }
}

public function down()
{
    Schema::drop('users');
}

// 2015_06_17_300000_create_vehicles_table.php

class CreateVehiclesTable extends Migration
{
    public function up()
    {
        Schema::create('vehicles', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id')->unsigned();
            $table->string('make');
            $table->string('model');
            $table->string('year');
            $table->string('color');
            $table->string('plate');
            $table->timestamps();

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

public function down()
{
    Schema::drop('vehicles');
}

【问题讨论】:

  • 它试图在第一次迁移时为数据库播种,因为您传递了--seed 选项。您的迁移很好,问题在于播种。你能添加车辆表播种器的代码吗?
  • 您可能还想尝试delete() 而不是truncate()。那应该可以。
  • 嗨 @user3158900,我在 DatabaseSeeder 中找到了它。我添加了 delete() 来代替,它可以工作。如果您发布为答案,我会将其标记为正确。

标签: mysql laravel laravel-5 laravel-migrations laravel-seeding


【解决方案1】:
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
App\User::truncate();
DB::statement('SET FOREIGN_KEY_CHECKS=1;');

而且有效!

【讨论】:

  • 跳过外键检查是一种非常糟糕的做法。例如,截断会重置自动递增的 ID,因此从此时起您的关系将是错误的
  • @CommonToast 我同意你的观点,在谈到现实世界的数据时,这是一种不好的做法,但在新建项目中,这可能有助于创建迁移和种子。如果孤立数据可能发生在大型和多方案环境中,您如何修复这些孤立数据?
【解决方案2】:

正如错误所说,您不能截断外键引用的表。删除应该可以工作...

DB::table('some_table')->delete();

【讨论】:

    【解决方案3】:

    掉落前

    Schema::disableForeignKeyConstraints();
    

    和之前关闭运行方法

    Schema::enableForeignKeyConstraints();
    

    【讨论】:

    • 最佳答案在这里
    【解决方案4】:

    clear table 使用Eloquent

    Model::query()->delete();
    

    使用默认用户模型的示例

    User::query()->delete();
    

    【讨论】:

      【解决方案5】:

      我的角色和权限设置也遇到了同样的问题,这就是我所做的,它按我的意愿工作。 Truncate() 会将增量列重置为 1,但会引发外键错误,而另一方面,删除工作正常但不会重置增量列,因此我在 Seeder 的文件中执行了以下操作(在我的情况下为 RoleSeeder.php )

      1. [删除()方法]

      $roles = [];
      
      ... // Some foreach statement to prepare an array of data for DB insert()
      
      // Delete and Reset Table
      DB::table('roles')->delete();
      DB::statement("ALTER TABLE `roles` AUTO_INCREMENT = 1");
      // Insert into table
      DB::table('roles')->insert($roles);
      

      这将级联附加到 roles 表的所有其他子表。在我的情况下 users_roles 表。这样我就避免了禁用和启用外键检查。

      2。要记住的事情/第二种方法[截断()方法]

      如果您不打算删除存储在子表中的所有数据(在我的情况下为 users_roles 表)...您可以使用 truncate() 然后在 DatabaseSeeders.php 文件中禁用和启用外键检查。当我对此进行测试并且 users_roles 数据完好无损时,受影响角色表上的种子。

      //RoleSeeders.php File
      
      $roles = [];
      
      ... // Some foreach statement to prepare an array of data for DB insert()
      
      // Truncate Table
      DB::table('roles')->truncate();
      // Insert into table
      DB::table('roles')->insert($roles);
      

      然后在 DatabaseSeeder.php 文件中执行;

      public function run()
      {
          DB::statement('SET FOREIGN_KEY_CHECKS=0;');
      
          $this->call([
              RoleSeeder::class,
          ]);
      
          DB::statement('SET FOREIGN_KEY_CHECKS=1;');
      }
      

      但我更喜欢 delete() 方法,因为我不必禁用/启用外键检查

      【讨论】:

        【解决方案6】:

        你可以使用

        DB::table('your_table_name')->delete();
        

        清空表,这不会删除表结构。但是自动递增id不会从初始数字开始。

        【讨论】:

          【解决方案7】:

          这就是每次都对我有用的方法。 添加外键时,请确保添加cascade。 语法是这样的

          $table->foreign('column')->references('id')->on('table_name')->onDelete('cascade');
          

          确保将id 替换为适用于您的任何字段。

          现在在运行播种之前添加这个而不是 trucate

          DB::statement('DELETE FROM table_name');
          

          它将删除所有数据。 希望这会有所帮助。

          【讨论】:

            【解决方案8】:

            你可以把它扔掉。

            $table->dropForeign('posts_user_id_foreign');

            【讨论】:

              【解决方案9】:

              我正在使用 Laravel 7.x,这对我有用。不用说它应该只用于开发。要了解更多信息,请查看here

              DatabaseSeeder.php

                  <?php
              
              use Illuminate\Database\Seeder;
              
              class DatabaseSeeder extends Seeder
              {
                  /**
                   * Seed the application's database.
                   *
                   * @return void
                   */
                  public function run()
                  {
                      // the Eloquent part and disabling and enabling of foreign keys is only intended for development
                      Eloquent::unguard();
              
                      //disable foreign key check for this connection before running seeders
                      DB::statement('SET FOREIGN_KEY_CHECKS=0;');
              
                      $this->call(RolesTableSeeder::class);
                      $this->call(UsersTableSeeder::class);
              
                      // supposed to only apply to a single connection and reset it's self
                      // but I like to explicitly undo what I've done for clarity
                      DB::statement('SET FOREIGN_KEY_CHECKS=1;');
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 2019-11-30
                • 2021-08-30
                • 1970-01-01
                • 2019-03-24
                • 2017-03-27
                • 2013-09-10
                • 2020-03-12
                • 2020-09-21
                相关资源
                最近更新 更多