Laravel Migration Change untuk Membuat Kolom Nullable

194

Saya membuat migrasi dengan unsigned user_id. Bagaimana saya bisa mengedit user_iddalam migrasi baru untuk membuatnya juga 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();
}
pengguna391986
sumber

Jawaban:

262

Laravel 5 sekarang mendukung pengubahan kolom; inilah contoh dari dokumentasi resmi:

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

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

Laravel 4 tidak mendukung kolom modifikasi, jadi Anda perlu menggunakan teknik lain seperti menulis perintah SQL mentah. Sebagai contoh:

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

}
MURATSPLAT
sumber
3
Terima kasih untuk ini. Tetapi bagaimana saya bisa membuat yang sebaliknya? Bagaimana cara mengubah kolom agar tidak dapat dibatalkan? Ada ide?
algoritme
@algorhythm Apakah Anda mencoba string '$ t-> ini (' name ', 100) -> change ();'
MURATSPLAT
7
Anda perlu meminta doktrin \ dbal untuk bermigrasi
younes0
33
@algoritme ->nullable(false)akan memungkinkan Anda mengubah kolom kembali.
Colin
9
-> change () mengharuskan Anda untuk menginstal paket DBTR Doctrine, dan itu secara inheren tidak mengenali semua jenis kolom yang sama yang tersedia di luar kotak dari laravel .. misalnya ganda bukan jenis kolom yang dikenali ke DBAL.
Will Vincent
174

Inilah jawaban lengkap untuk pembaca masa depan. Perhatikan bahwa ini hanya mungkin di Laravel 5+.

Pertama-tama Anda akan membutuhkan paket doktrin / dbal :

composer require doctrine/dbal

Sekarang dalam migrasi Anda, Anda dapat melakukan ini untuk membuat kolom nullable:

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

Anda mungkin bertanya-tanya bagaimana cara mengembalikan operasi ini. Sayangnya sintaks ini tidak didukung:

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

Ini adalah sintaks yang benar untuk mengembalikan migrasi:

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

Atau, jika Anda mau, Anda dapat menulis kueri mentah:

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

Semoga jawaban ini bermanfaat. :)

Dmitri Chebotarev
sumber
3
Ini adalah jawaban paling lengkap untuk L5, tetapi harus disebutkan bahwa jika 'user_id' adalah kunci asing, yang seharusnya, Anda tidak akan dapat mengubahnya kecuali jika Anda menjalankan 'DB :: statement (' SET FOREIGN_KEY_CHECKS = 0 ');' pertama. Dan atur kembali ke 1 setelah selesai.
rzb
1
Terima kasih, nullable(false)menyelamatkan saya dari mencabut rambut saya, karena nullable()tidak terdokumentasi dengan baik, dan tidak ada notNull()fungsi.
Zack Morris
ini tidak berfungsi untuk kunci asing dengan postgres. Mencoba SET FOREIGN_KEY_CHECKS = 0memberikan kesalahan. Anda mungkin perlu mengubah batasan tabel dengan menggunakan kueri mentah. lihat di sini: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz
Ini melanggar tes saya. Tes mulai berjalan dan kemudian digantung. Saya kira rollback pertama yang menyebabkan ini. Menyebabkan tes menggantung untuk MySQL dan SQLite.
Thomas Praxl
155

Saya berasumsi bahwa Anda mencoba mengedit kolom yang telah Anda tambahkan data, jadi menjatuhkan kolom dan menambahkan lagi sebagai kolom yang tidak dapat dibatalkan tidak mungkin tanpa kehilangan data. Kami akan alterkolom yang ada.

Namun, pembuat skema Laravel tidak mendukung memodifikasi kolom selain mengganti nama kolom. Jadi, Anda harus menjalankan kueri mentah untuk melakukannya, seperti ini:

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

Dan untuk memastikan Anda masih dapat mengembalikan migrasi Anda, kami akan melakukannya down()juga.

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

Satu catatan adalah bahwa karena Anda mengkonversi antara nullable dan tidak nullable, Anda harus memastikan Anda membersihkan data sebelum / setelah migrasi Anda. Jadi lakukan itu di skrip migrasi Anda dengan dua cara:

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;');
}
Unnawut
sumber
7
Untuk Laravel 4, ganti querydenganstatement
Razor
2
Terima kasih @Razor. Memperbarui jawaban saya sesuai dengan itu.
Unnawut
1
Dalam downfungsi di blok kode kedua, pernyataan SQL harus diakhiri dengan NOT NULL. ( downFungsi dalam contoh ketiga benar.)
Scott Weldon
46

Dia migrasi penuh untuk 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();
    });
}

Intinya, Anda bisa menghapus nullabledengan meneruskan falsesebagai argumen.

Yauheni Prakopchyk
sumber
16

Jika Anda mengubah kolom dan tersandung

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

maka cukup instal

composer require doctrine/dbal

ken
sumber
1
Ini menggigit saya, jadi saya melanjutkan dan membuat pengecualian / solusi lebih mudah untuk diikuti: github.com/laravel/framework/pull/10002
Beau Simensen
9

Menambahkan ke jawaban Dmitri Chebotarev, seperti untuk Laravel 5+.

Setelah membutuhkan paket doktrin / dbal :

composer require doctrine/dbal

Anda kemudian dapat melakukan migrasi dengan kolom yang dapat dibatalkan, seperti:

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

Untuk mengembalikan operasi, lakukan:

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

Menambahkan ke Dmitri Chebotarev Answer,

Jika Anda ingin mengubah beberapa kolom sekaligus, Anda dapat melakukannya seperti di bawah ini

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;
');
Sameer
sumber
2

Cobalah:

$table->integer('user_id')->unsigned()->nullable();
Adil
sumber
1
Itu tidak mengubah kolom yang ada
dVaffection
9
Anda lupa ->changedi bagian akhir dan hanya menyebutkannya Laravel 5+
Alexander Malakhov
Anda perlu memintacomposer require doctrine/dbal
Lizesh Shakya
2

Untuk Laravel 4.2, jawaban Unnawut di atas adalah yang terbaik. Tetapi jika Anda menggunakan awalan tabel, maka Anda perlu sedikit mengubah kode Anda.

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

Dan untuk memastikan Anda masih dapat mengembalikan migrasi Anda, kami akan melakukannya down()juga.

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