Зміна міграції Laravel зробить стовпчиком нульовим


194

Я створив міграцію з непідписаним user_id. Як я можу редагувати user_idнову міграцію, щоб її також зробити nullable()?

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    // this needs to also be nullable, how should the next migration be?
    $table->integer('user_id')->unsigned();
}

Відповіді:


265

Laravel 5 тепер підтримує зміну стовпця; ось приклад із офіційної документації:

Schema::table('users', function($table)
{
    $table->string('name', 50)->nullable()->change();
});

Джерело: http://laravel.com/docs/5.0/schema#changing- Column

Laravel 4 не підтримує модифікування стовпців, тому вам знадобиться використовувати інший метод, такий як написання необробленої команди SQL. Наприклад:

// getting Laravel App Instance
$app = app();

// getting laravel main version
$laravelVer = explode('.',$app::VERSION);

switch ($laravelVer[0]) {

    // Laravel 4
    case('4'):

        DB::statement('ALTER TABLE `pro_categories_langs` MODIFY `name` VARCHAR(100) NULL;');
        break;

    // Laravel 5, or Laravel 6
    default:                

        Schema::table('pro_categories_langs', function(Blueprint $t) {
            $t->string('name', 100)->nullable()->change();
        });               

}

3
Thx для цього. Але як я можу зробити протилежне? Як змінити стовпчик, щоб він не був нульовим? Будь-які ідеї?
алгоритм

@algorhythm Ви спробуєте цей рядок '$ t-> (' ім'я ', 100) -> change ();'
МУРАТСПЛАТ

7
Вам потрібно вимагати доктрини \ dbal для міграції
younes0

33
@algorhythm ->nullable(false)дозволить вам знову змінити стовпець назад.
Колін

9
-> change () вимагає встановити пакет DBAL Doctrine DBAL, і він по суті не розпізнає всі ті самі типи стовпців, які доступні у вікні від laravel.
Буде Вінсент

175

Ось повна відповідь для майбутнього читача. Зауважте, що це можливо лише в Laravel 5+.

Перш за все вам знадобиться пакет доктрин / dbal :

composer require doctrine/dbal

Тепер під час міграції ви можете це зробити, щоб стовпчик мінявся:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Вам може бути цікаво, як відновити цю операцію. На жаль, цей синтаксис не підтримується:

// Sadly does not work :'(
$table->integer('user_id')->unsigned()->change();

Це правильний синтаксис для повернення міграції:

$table->integer('user_id')->unsigned()->nullable(false)->change();

Або, якщо хочете, можете написати необслугований запит:

public function down()
{
    /* Make user_id un-nullable */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Сподіваємось, ця відповідь стане корисною. :)


4
Це найповніша відповідь для L5, але слід зазначити, що якщо 'user_id' - це зовнішній ключ, яким він повинен бути, ви не зможете його змінити, якщо не запустите оператор DB: (SET FOREIGN_KEY_CHECKS = 0 ');' перший. І поверніть його на 1, коли закінчите.
rzb

1
Дякую, nullable(false)врятували мене від витягування волосся, бо nullable()це не добре документально підтверджено, і немає notNull()функції.
Зак Морріс

це не працює для зовнішніх ключів з постгресами. спроба SET FOREIGN_KEY_CHECKS = 0видає помилку. вам, ймовірно, доведеться змінити обмеження таблиці, використовуючи необроблений запит. дивіться тут: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz

Це порушує мої тести. Тести починають працювати і потім висіти. Я думаю, що перший відкат викликає це. Викликає вивішування тестів як для MySQL, так і для SQLite.
Томас Праксл

155

Я припускаю, що ви намагаєтесь відредагувати стовпчик, про який ви вже додали дані, тому викидання стовпця та додавання знову як нульовий стовпець неможливе без втрати даних. Ми будемо alterнаявним стовпцем.

Однак конструктор схем Laravel не підтримує модифікацію стовпців, крім перейменування стовпця. Тому для їх виконання потрібно буде виконати необроблені запити:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

І щоб переконатися, що ви все ще можете відкатати свою міграцію, ми також зробимо це down().

function down()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Одне зауваження полягає в тому, що оскільки ви конвертуєте між нульовими та ненульовими, вам потрібно переконатися, що ви очищаєте дані до / після міграції. Тож зробіть це у вашому сценарії міграції двома способами:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE `throttle` SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down()
{
    DB::statement('UPDATE `throttle` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

7
Для Laravel 4 замінити queryнаstatement
Бритва

2
Дякую @Razor Відповідно оновив мою відповідь.
Unnawut

1
У downфункції другого кодового блоку оператор SQL повинен закінчуватися NOT NULL. ( downФункція в третьому прикладі правильна.)
Скотт Велдон,

46

Він повна міграція для Laravel 5 :

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable()->change();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable(false)->change();
    });
}

Справа в тому, що ви можете видалити nullable, передавши falseяк аргумент.


16

Якщо трапляється міняти стовпці і натрапляють на

'Doctrine\DBAL\Driver\PDOMySql\Driver' not found

то просто встановіть

composer require doctrine/dbal


1
Це трохи мене, тому я пішов вперед і полегшив виняток / рішення: github.com/laravel/framework/pull/10002
Beau Simensen

9

Додаючи відповідь Дмитра Чеботарева, як і для Laravel 5+.

Після того, як вимагає / DBAL доктрини пакета:

composer require doctrine/dbal

Потім можна зробити міграцію за допомогою змінних стовпців, наприклад:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Щоб відновити операцію, виконайте:

public function down()
{
    /* turn off foreign key checks for a moment */
    DB::statement('SET FOREIGN_KEY_CHECKS = 0');
    /* set null values to 0 first */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    /* alter table */
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
    /* finally turn foreign key checks back on */
    DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}

3

Додаючи відповідь Дмитра Чеботарева,

Якщо ви хочете змінити кілька стовпців одночасно, ви можете зробити це як нижче

DB::statement('
     ALTER TABLE `events` 
            MODIFY `event_date` DATE NOT NULL,
            MODIFY `event_start_time` TIME NOT NULL,
            MODIFY `event_end_time` TIME NOT NULL;
');


2

Для Laravel 4.2 відповідь Unnawut вище є найкращою. Але якщо ви використовуєте префікс таблиці, вам потрібно трохи змінити код.

function up()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

І щоб переконатися, що ви все ще можете відкатати свою міграцію, ми також зробимо це down().

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.