Laravel - миграция, изменение структуры таблицы - правильный путь - PullRequest
1 голос
/ 04 октября 2019

Моя нынешняя таблица

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_id, standard_id и school_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
        });
    }

, нопохоже, что он не работает.

Ошибка

Подсветка \ База данных \ QueryException: SQLSTATE [23000]: Нарушение ограничения целостности: 1452 Невозможно добавить или обновитьдочерняя строка: сбой ограничения внешнего ключа (myapp_extra. #sql-2f78_29d, CONSTRAINT students_standard_id_foreign ИНОСТРАННЫЙ КЛЮЧ (standard_id) ОБРАТНАЯ СВЯЗЬ standards (id) НА УДАЛИТЬ КАСКАД НА ОБНОВЛЕНИЕ КАСКАД) (SQL: изменить таблицуstudents добавить ограничение students_standard_id_foreign ссылки на внешний ключ (standard_id) standards (id) при удалении каскада при обновлении каскада)

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

Примечание : таблица стандартов и разделов создается до выполнения этой миграции, поэтому доступны оба столбца.

1 Ответ

1 голос
/ 04 октября 2019

Почему это происходит?

Эта ошибка возникает из-за того, что вы вставляете новый столбец без значения по умолчанию и без NULLABLE в таблицу, в которой уже есть строки.

Когда вы это делаетеMySQL установит для него значение 0, поэтому во всех ваших таблицах standard_id и section_id будут установлены 0, поэтому при попытке добавить внешний индекс произойдет сбой, поскольку 0 недопустимоидентификатор вашей standards / sections таблицы.

Итак, как это исправить?

У вас есть несколько способов решить эту проблему:

1-й: Установка значения по умолчанию

Если это имеет смысл для вашего приложения, вы можете установить для столбца значение по умолчанию (действительное), чтобы внешний ключ не вышел из строя:

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

В большинстве случаев это не так просто, поэтому вам нужно определить значение динамически

2-й: Установка значения динамически

Если у вас есть логика для установки значения по умолчанию для этих новых столбцов, вы можете разбить вашу миграцию на двашаги:

// 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
});

3-й: сделать поле обнуляемым

IЕсли вы просто не знаете или не имеете значения по умолчанию для этих полей, то вместо этого ваше поле должно иметь значение NULL:

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