【问题标题】:how to alter enum type column in migration in testing laravel如何在测试 laravel 中更改迁移中的枚举类型列
【发布时间】:2020-11-22 08:42:26
【问题描述】:

假设我有一个在生产环境中运行的代码,因此,我无法更改相同的迁移文件以添加新列,如下所示

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name')->nullable();
            $table->string('email')->unique();
            $table->string('token_key')->unique()->nullable();
            $table->enum('type', ['avatar', 'image', 'video'])->comment(implode(', ', ['avatar', 'image', 'video']));
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

在第一个版本之后,我想从名为 type 可接受值的列中删除 avatar 值,所以我添加了一个新的迁移文件来添加我的新列,如下所示

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ChangeEnumOnUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        $sql = sprintf(
            "ALTER TABLE %s CHANGE `%s` `%s` ENUM('%s') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '%s'",
            'users',
            'type',
            'type',
            implode('\',\'', ['image', 'video']),
            implode(',', ['image', 'video'])
        );
        DB::statement($sql);
    }
}

并使用vendor/bin/phpunit 我运行我的测试

请注意,首先数据库将被迁移,并且由于该测试方法没有启动

SQLite 抛出如下错误。

SQLite 异常是这样的

PDOException: SQLSTATE[HY000]: General error: 1 near "CHANGE": syntax error

Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 near "CHANGE": syntax error (SQL: ALTER TABLE users CHANGE `type` `type` ENUM('image','video') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'image,video')

【问题讨论】:

  • 您好,欢迎来到 SO。如果没有详细信息,这将是一个很难解决的问题。添加第二次迁移的内容将是一个很好的输入。你有什么尝试让它发挥作用。

标签: php laravel sqlite testing phpunit


【解决方案1】:

您不得使用DB::statementsprintf 修改您的字段。

所以你可以像这样使用 Laravel 迁移机制的内置函数change

Schema::table('users', function (Blueprint $table) {
    $table->string('name', 50)->change(); // update the field by increasing the max allowed characters
});

请参阅:Laravel Migration: Modifying Columns

【讨论】:

    【解决方案2】:

    我已经搜索并找到了这个解决方案,希望有用。

    我的问题是数据库的行为和对键的支持,当您使用 laravel 的迁移功能来更改 enum 类型时,您必须首先将 doctrine/dbal 包添加到您的项目中

     composer require doctrine/dbal
    

    那么您必须将enum 类型添加到学说中,因为 laravel 正在使用该包来操作表列,并且此 laravel 默认情况下没有将enum 类型添加到学说中,因此您需要更改迁移中的 __construct 方法,如下所示

    use Doctrine\DBAL\Types\Type;
    use Doctrine\DBAL\Types\StringType;
    
    public function __construct()
    {
        if (! Type::hasType('enum')) {
            Type::addType('enum', StringType::class);
        }
        DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
    }
    

    然后您可以更改您的enum 列,如下所示

    $table->enum('type', ['avatar', 'video'])
          ->comment(implode(', ', ['avatar', 'video']))
          ->change();
    

    并且知道在测试中更改枚举类型字段没有问题。

    注意: 此解决方案是doctrine project's site 上的ENUM 类型提供的解决方案之一,它提供两种解决方案,第一个是Mapping to varchars,第二个是Defining a custom type for enum

    如果上述解决方案对您不起作用,那么您可以在doctrine project's siteyourself 中阅读有关此问题以及如何解决它的更多信息

    【讨论】:

    • 这不起作用 - 迁移将成功运行,但您的列(根据我的经验)从枚举转换为 varchar。这不是预期的行为
    • @sudoyum 感谢您的评论,我确实添加了学说项目的站点以获得更多解决方案,该站点清楚地说明了问题和解决方案,我希望这个解决方案对您有用
    猜你喜欢
    • 2019-12-08
    • 2023-03-28
    • 2023-03-07
    • 2020-03-13
    • 2021-01-08
    • 2015-09-01
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多