首页 > 解决方案 > Laravel - 迁移,表结构修改 - 正确方法

问题描述

我现在的桌子是

Schema::create('students', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->string('first_name', 255);
    $table->string('last_name', 255);
    $table->enum('gender', ['m', 'f']);
    $table->date('date_of_birth');
    $table->integer('roll_number');
    $table->char('section', 1);
    $table->integer('class');
    $table->unsignedBigInteger('school_id');            
    $table->string('photo')->nullable;
    $table->timestamps();

    $table->foreign('school_id')
        ->references('id')->on('schools')
        ->onUpdate('cascade')->onDelete('cascade');

    $table->unique(['roll_number', 'section', 'class', 'school_id']);
});

标准

Schema::create('standards', function (Blueprint $table) {
       $table->bigIncrements('id');
       $table->string('name');
       $table->unsignedBigInteger('school_id');
       $table->timestamps();

       $table->foreign('school_id')
       ->references('id')->on('schools')
       ->onUpdate('cascade')->onDelete('cascade');
    });

部分

Schema::create('sections', function (Blueprint $table) {
    $table->bigIncrements('id');
    $table->char('name', 1);
    $table->unsignedBigInteger('standard_id');
    $table->timestamps();

    $table->foreign('standard_id')
    ->references('id')->on('standards')
    ->onUpdate('cascade')->onDelete('cascade');
});

现在我有标准和节表,这些表中的外键将替换现有结构中的类和节列,并保持、roll_number和的组合是唯一的。section_idstandard_idschool_id

我试过了

 public function up()
    {
        Schema::table('students', function (Blueprint $table) {
            $table->dropUnique(['roll_number', 'section', 'class', 'school_id']);

            $table->dropColumn('section');
            $table->dropColumn('class');
            $table->unsignedBigInteger('standard_id')->after('roll_number');
            $table->unsignedBigInteger('section_id')->after('standard_id');

            $table->foreign('standard_id')->references('id')->on('standards')
            ->onUpdate('cascade')->onDelete('cascade');
            $table->foreign('section_id')->references('id')->on('sections')
            ->onUpdate('cascade')->onDelete('cascade');

            $table->unique(['roll_number', 'standard_id', 'section_id', 'school_id']); // unique combination
        });
    }

但它似乎不起作用。

错误

Illuminate\Database\QueryException:SQLSTATE[23000]:完整性约束违规:1452 无法添加或更新子行:外键约束失败(myapp_extra. #sql-2f78_29d,CONSTRAINT students_standard_id_foreignFOREIGN KEY(standard_id)REFERE NCES standardsid)ON DELETE CASCADE ON UPDATE CASCADE)(SQL :更改表students添加约束students_standard_id_foreign 外键(standard_id)引用standardsid)删除级联更新级联)

  at \myapp\vendor\laravel\framework\src\Illuminate\Database\Connection.php:664

注意:标准和部分表是在进行此迁移之前创建的,因此这两列都可用。

标签: phpmysqllaravellaravel-5.8laravel-migrations

解决方案


为什么会发生这种情况?

发生此错误是因为您正在插入一个没有默认值的新列,并且没有插入NULLABLE已经有行的表。

当您执行此操作时,MySQL 会将其值设置为0,因此您的所有表都将具有standard_idsection_id设置为0,因此当您尝试添加外部索引时,它会失败,因为/表0上的 id 无效。standardssections

那么如何修复呢?

你有一些方法可以解决这个问题:

第一种:设置默认值

如果对您的应用程序有意义,您可以为您的列设置一个默认(有效)值,这样外键就不会失败:

        $table->unsignedBigInteger('standard_id')->default(1)->after('roll_number');
        $table->unsignedBigInteger('section_id')->default(1)->after('standard_id');

大多数时候它不是那么简单,所以你需要动态定义值

第二:动态设置值

如果您有一些逻辑来设置此新列的默认值,则可以将迁移分为两个步骤:

// Add the fields first
Schema::table('students', function (Blueprint $table) {
        $table->dropUnique(['roll_number', 'section', 'class', 'school_id']);

        $table->dropColumn('section');
        $table->dropColumn('class');
        $table->unsignedBigInteger('standard_id')->after('roll_number');
        $table->unsignedBigInteger('section_id')->after('standard_id');
}

App\Students::get()->each(function($student) {
    // Apply your logic here
    $student->standard_id = 3;
    $student->section_id = 3;
    $student->save();
});

// Now you can add your foreign keys.
Schema::table('students', function (Blueprint $table) {
        $table->foreign('standard_id')->references('id')->on('standards')
        ->onUpdate('cascade')->onDelete('cascade');
        $table->foreign('section_id')->references('id')->on('sections')
        ->onUpdate('cascade')->onDelete('cascade');

        $table->unique(['roll_number', 'standard_id', 'section_id', 'school_id']); // unique combination
});

第三:使字段可以为空

如果您只是不知道或没有此字段的默认值,那么您的字段应该可以为空:

    $table->unsignedBigInteger('standard_id')->nullable()->after('roll_number');
    $table->unsignedBigInteger('section_id')->nullable()->after('standard_id');

推荐阅读