Modifica della migrazione di Laravel per rendere nullable una colonna


194

Ho creato una migrazione con unsigned user_id. Come posso modificare user_idin una nuova migrazione per farlo anche 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();
}

Risposte:


266

Laravel 5 ora supporta la modifica di una colonna; ecco un esempio dalla documentazione ufficiale:

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

Fonte: http://laravel.com/docs/5.0/schema#changing-columns

Laravel 4 non supporta la modifica delle colonne, quindi dovrai usare un'altra tecnica come scrivere un comando SQL non elaborato. Per esempio:

// 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
Grazie per questo. Ma come posso fare il contrario? Come modificare una colonna per non essere nullable? Qualche idea?
algoritmo

@algorhythm Provi questa '$ t-> string (' name ', 100) -> change ();'
MURATSPLAT,

7
Devi migrare su dottrina \ dbal
younes0,

33
@algorhythm ->nullable(false)ti consente di modificare nuovamente la colonna.
Colin,

9
-> change () richiede l'installazione del pacchetto DBAL di Doctrine e non riconosce intrinsecamente tutti gli stessi tipi di colonna disponibili immediatamente da laravel .. ad esempio double non è un tipo di colonna riconosciuto in DBAL.
Will Vincent,

175

Ecco la risposta completa per il futuro lettore. Nota che questo è possibile solo in Laravel 5+.

Prima di tutto avrai bisogno del pacchetto dottrine / dbal :

composer require doctrine/dbal

Ora nella tua migrazione puoi farlo per rendere nulla la colonna:

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

Forse ti starai chiedendo come ripristinare questa operazione. Purtroppo questa sintassi non è supportata:

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

Questa è la sintassi corretta per ripristinare la migrazione:

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

Oppure, se preferisci, puoi scrivere una query non elaborata:

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

Spero che troverai utile questa risposta. :)


4
Questa è la risposta più completa per L5, ma va detto che se 'user_id' è una chiave esterna, che dovrebbe essere, non sarai in grado di cambiarla se non esegui 'DB :: statement (' SET FOREIGN_KEY_CHECKS = 0 ');' primo. E riportalo a 1 quando hai finito.
rzb,

1
Grazie, nullable(false)mi ha salvato dal strapparmi i capelli, perché nullable()non è ben documentato e non ha alcuna notNull()funzione.
Zack Morris,

questo non funziona per le chiavi esterne con Postgres. provare SET FOREIGN_KEY_CHECKS = 0dà un errore. probabilmente dovrai modificare i vincoli della tabella usando una query non elaborata. vedi qui: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz

Questo sta rompendo i miei test. I test iniziano a funzionare e quindi si bloccano. Suppongo che il primo rollback causi questo. Provoca i test di sospensione per MySQL e SQLite.
Thomas Praxl,

155

Suppongo che tu stia cercando di modificare una colonna su cui hai già aggiunto dati, quindi non è possibile rilasciare una colonna e aggiungerla di nuovo come colonna nullable senza perdere dati. Vedremo alterla colonna esistente.

Tuttavia, il generatore di schemi di Laravel non supporta la modifica di colonne diverse dalla ridenominazione della colonna. Quindi dovrai eseguire query non elaborate per eseguirle, in questo modo:

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

E per essere sicuri di poter ancora ripristinare la migrazione, faremo anche noi down().

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

Una nota è che dal momento che stai convertendo tra nullable e non nullable, dovrai assicurarti di ripulire i dati prima / dopo la migrazione. Quindi, fallo nel tuo script di migrazione in entrambi i modi:

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
Per Laravel 4, sostituisci queryconstatement
Razor il

2
Grazie @Razor. Aggiornato di conseguenza la mia risposta.
Unnawut,

1
Nella downfunzione nel secondo blocco di codice, l'istruzione SQL dovrebbe terminare con NOT NULL. (La downfunzione nel terzo esempio è corretta.)
Scott Weldon,

46

È la migrazione completa per 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();
    });
}

Il punto è che puoi rimuoverlo nullablepassando falsecome argomento.



9

Aggiungendo alla risposta di Dmitri Chebotarev, come per Laravel 5+.

Dopo aver richiesto il pacchetto dottrine / dbal :

composer require doctrine/dbal

È quindi possibile effettuare una migrazione con colonne nullable, in questo modo:

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

Per ripristinare l'operazione, eseguire:

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

Aggiungendo alla risposta Dmitri Chebotarev,

Se vuoi modificare più colonne alla volta, puoi farlo come di seguito

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

Per Laravel 4.2, la risposta di Unnawut sopra è la migliore. Ma se si utilizza il prefisso della tabella, è necessario modificare leggermente il codice.

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

E per essere sicuri di poter ancora ripristinare la migrazione, faremo anche noi down().

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.