Laravel迁移-更新枚举选项

eeq64g8w  于 2022-12-24  发布在  其他
关注(0)|答案(5)|浏览(117)

我尝试使用模式构建器向表添加枚举选项(而不丢失当前数据集)。
我唯一真正能够找到的关于列更改的是http://www.flipflops.org/2013/05/25/modify-an-existing-database-column-in-a-laravel-migration/,我相信这是为Laravel 3编写的。
即便如此,我还是尝试使用DB::query('ALTER TABLE...');命令,但它因call_user_func_array()而出错,预期参数1为有效回调,类“Illuminate\Database\MySqlConnection”没有方法“query”。

DB::query("ALTER TABLE users CHANGE COLUMN permissions permissions ENUM('admin', 'user', 'candidate')");

我也试过这样做:

Schema::table('users', function ($table) {
    $table->enum('permissions', array('admin', 'user', 'candidate'))->default('user');
});

但它会出错,说该列已经存在。
在不丢失该列中所有数据的情况下,执行我尝试执行的操作的最佳方法是什么?

liwlm1x9

liwlm1x91#

使用DB::statement方法:

DB::statement("ALTER TABLE users CHANGE COLUMN permissions permissions ENUM('admin', 'user', 'candidate') NOT NULL DEFAULT 'user'");
gajydyqb

gajydyqb2#

我已经将Joseph's answer修改为一个方法,您可以将其添加到迁移中,然后使用一个值数组调用,而不是将其硬编码到语句中。它没有对带引号的值进行任何花哨的处理,因此请只使用合理的值,或者自己修改它。

private function setEnumValues($table, $column, array $values, $nullable = false, $default = null)
{
    $quotedValues = collect($values)
        ->map(function ($value) {
            return "'${value}'";
        })
        ->join(', ');

    $suffix = '';

    if (!$nullable) {
        $suffix .= ' NOT NULL';
    }

    if ($default) {
        $suffix .= " DEFAULT '${default}'";
    }

    $statement = <<<SQL
ALTER TABLE ${table} CHANGE COLUMN ${column} ${column} ENUM(${quotedValues}) ${suffix}
SQL;

    \Illuminate\Support\Facades\DB::statement($statement);
}

您可以在迁移中使用它,如下所示:

<?php

use Illuminate\Database\Migrations\Migration;

class AddQueuedStatusToPaymentsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        // Add the new 'queued' value

        $this->setEnumValues(
            'payments',
            'status',
            [
                'queued',
                'processing',
                'successful',
                'failed',
            ],
            false, // Not nullable
            'queued' // Mark it as the default for all new payments
        );
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        // Remove the new 'queued' value
        
        $this->setEnumValues(
            'payments',
            'status',
            [
                'processing',
                'successful',
                'failed',
            ],
            false, // Not nullable
            'processing' // Set the default back to processing for all new payments
        );
    }

    private function setEnumValues($table, $column, array $values, $nullable = false, $default = null)
    {
        $quotedValues = collect($values)
            ->map(function ($value) {
                return "'${value}'";
            })
            ->join(', ');

        $suffix = '';

        if (!$nullable) {
            $suffix .= ' NOT NULL';
        }

        if ($default) {
            $suffix .= " DEFAULT '${default}'";
        }

        $statement = <<<SQL
ALTER TABLE ${table} CHANGE COLUMN ${column} ${column} ENUM(${quotedValues}) ${suffix}
SQL;

        \Illuminate\Support\Facades\DB::statement($statement);
    }
}
nxagd54h

nxagd54h3#

如果以上选项都不适合您,try this old solution。它仍然有效。这是在我的情况下唯一有效的。

DB::transaction(function () {
    DB::statement('ALTER TABLE mytable DROP CONSTRAINT mytable_status_check;');
    DB::statement('ALTER TABLE mytable ADD CONSTRAINT mytable_status_check CHECK (status::TEXT = ANY (ARRAY[\'pending\'::CHARACTER VARYING, \'accepted\'::CHARACTER VARYING, \'canceled\'::CHARACTER VARYING]::TEXT[]))');
});

my_table”是表的名称,“status”是枚举列的名称

gojuced7

gojuced74#

在我的例子中,我想将"Wide_Skyscraper"添加到现有的枚举选项中,可接受的答案指向使用DB::transactionDB::statement的解决方案,但没有一个答案指出在将RAW语句输入到SQL中时尝试/捕获wrap和rollBack的安全方法。
迁移文件的UP方法:

use Illuminate\Support\Facades\DB;

//...

public function up()
{
    try {
        DB::transaction(function () {
            DB::statement("ALTER TABLE `advertisements` MODIFY COLUMN `type` ENUM('MREC', 'Skyscraper', 'Landscape', 'Wide_Skyscraper')");
        });
    } catch (Exception $e) {
        DB::rollBack();
    }
}

你可以只在down方法中添加一个注解,不要删除这个方法。

public function down()
{
    // Do nothing.
}

希望这能帮到什么人。

83qze16e

83qze16e5#

修改列
先决条件
在修改列之前,请确保将doctrine/dbal相关性添加到composer.json文件中。Doctrine DBAL库用于确定列的当前状态,并创建对列进行指定调整所需的SQL查询:

Schema::table('users', function (Blueprint $table) { 
    $table->enum('name', [])->change(); 
});

https://laravel.com/docs/5.8/migrations#modifying-columns

相关问题