Laravel 5.1 请求未知数据库类型枚举

Posted

技术标签:

【中文标题】Laravel 5.1 请求未知数据库类型枚举【英文标题】:Laravel 5.1 Unknown database type enum requested 【发布时间】:2016-01-13 10:59:54 【问题描述】:

在运行 php artisan migrate 时,出现以下错误

[Doctrine\DBAL\DBALException] 请求的未知数据库类型枚举,Doctrine\DBAL\Platforms\mysqlPlatform 可能不支持它。

如何解决此问题。

代码:

public function up() 
    Schema::table('blogs', function (Blueprint $table) 
        $table->string('wordpress_id')->nullable();
        $table->string('google_blog_id')->nullable()->change();
    );

【问题讨论】:

请发布您要迁移的架构。 public function up() Schema::table('blogs', function (Blueprint $table) $table->string('wordpress_id')->nullable(); $table-> string('google_blog_id')->nullable()->change(); ); 您的表是否包含enum 列? 是的.. 它有一个枚举类型字段。在另一个迁移中(但此迁移工作正常),我有以下 'DB::statement('ALTER TABLE blogs MODIFY type enum("wordpress","blogger") NULL;');' Laravel 目前不支持用枚举列重命名表中的列。如果您尝试更改另一列,则无关紧要。如果表中包含enum,它将不起作用。恐怕您将不得不以某种方式手动更改它,或者尝试一些相当丑陋的黑客或解决方法。 【参考方案1】:

官方 Laravel 5.1 documentation 声明:

注意:目前不支持使用枚举列重命名表中的列。

如果您尝试更改另一列并不重要,如果该表包含enum 任何地方,它将无法正常工作。这是一个 Doctrine DBAL 问题。

作为一种解决方法,您可以删除该列并添加一个新列(列数据将丢失):

public function up()

    Schema::table('users', function(Blueprint $table)
    
        $table->dropColumn('name');
    );

    Schema::table('users', function(Blueprint $table)
    
        $table->text('username');
    );

或使用 DB 语句:

public function up()

    DB::statement('ALTER TABLE projects CHANGE slug url VARCHAR(200)');


public function down()

    DB::statement('ALTER TABLE projects CHANGE url slug VARCHAR(200)');

来源:https://github.com/laravel/framework/issues/1186

【讨论】:

感谢您的解决方案,并非总是可以删除列,因此应该手动更改 如果你不使用$table,你不需要Schema环绕DB::statement 太糟糕了!我试图更新与枚举无关的列,这正在发送异常。好的,我猜 DB::statement 是这里的最佳选择。谢谢。 我更喜欢第二种方法,因为第一种方法会影响数据,因为它会删除并重新创建列。但第二种方法只会影响表结构。 doctrine/dbal 到底有什么问题,他们不能让你做一些用 SQL 查询很容易完成的事情?【参考方案2】:

这是 Laravel 5.1 documentation 中所述的一个已知问题。

注意:目前不支持重命名 具有enum 的表中的列。

当您的数据库表中有 enum 列时,就会发生这种情况。无论您是尝试重命名另一列,还是将另一列更改为nullable,都会出现此错误。这是Doctrine\DBAL 的问题。

一个简单的解决方法就是在你的数据库迁移文件中添加这个构造方法。

public function __construct()

    DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

这会将所有ENUM 列映射到VARCHAR(),并且该列将接受任何字符串。

这在 Laravel 5.1 和 Laravel 5.3 上对我有用。我希望这个错误可以尽快修复。

感谢@Gmatkowski 的回答 https://***.com/a/32860409/1193201

【讨论】:

这应该是公认的答案!谢谢@Xeleon 这会改变全局的类型映射,还是仅仅针对它指定的迁移?如果它是全球性的,这会不会有任何其他副作用?可以肯定的是,我使用了旧的 Laravel 4 方式,它也可以工作 (laraveldaily.com/…)。 我必须将该行添加到AppServiceProvider::boot() 才能使其正常工作。 感谢工作。我刚刚在 6.x 上遇到了这个问题,我发现这个已知问题到现在仍然存在于 8.x 像魅力一样工作。【参考方案3】:

一个真正肮脏的解决方案,可以完成工作,但会是

update Doctrine/DBAL/Schema/MySqlSchemaManager.php 

通过在第 113 行上方添加这些行

$this->_platform->registerDoctrineTypeMapping('enum', 'string');
$type = $this->_platform->getDoctrineTypeMapping($dbType);

请注意,不建议直接更新供应商文件,因为如果 vonder 选择更新插件,您的更改可能会被覆盖

【讨论】:

我正在做,但它不起作用。 protected function _getPortableDatabaseDefinition($database) $this->_platform->registerDoctrineTypeMapping('enum', 'string'); $type = $this->_platform->getDoctrineTypeMapping($dbType); return $database['Database']; 编辑供应商文件从不是一个合适的答案,不管你在它后面放了多少“小心”。【参考方案4】:

我通过创建一个新的迁移类并从它扩展我的迁移来解决这个问题。也许有多种方法可以让它更“标准”,但这只是一个非常简单的案例,非常适合我们的团队。

use Doctrine\DBAL\Types\StringType, Type;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB, Log;

/**
 * Class ExtendedMigration
 * Use it when the involved table(s) has enum type column(s)
 */
class ExtendedMigration extends Migration

    /**
     * ExtendedMigration constructor.
     * Handle Laravel Issue related with modifying tables with enum columns
     */
    public function __construct()
    
        try 
            Type::hasType('enum') ?: Type::addType('enum', StringType::class);
            Type::hasType('timestamp') ?: Type::addType('timestamp', DateTimeType::class);
         catch (\Exception $exception) 
            Log::info($exception->getMessage());
        
    

然后如前所述,扩展您的迁移

class SampleMigration extends ExtendedMigration

    public function up()
    
        Schema::create('invitations', function (Blueprint $table) 
            ...
            $table->enum('status', ['sent', 'consumed', 'expired'])->default('sent');
            ...
        );
    

    public function down()
    
        Schema::dropIfExists('invitations');
    

【讨论】:

在哪里放置这个 ExtendedMigration?我成功地将类型直接添加到正常迁移的 up 函数中,但我很好奇您将 ExtendedMigration 类放在哪里 @Dika,根据你的项目类型,如果你正在构建一个库,将它放在数据库文件夹中可能是有意义的,在我的例子中,我们有一个常规的 Laravel 项目,我把它放在一个helpers 文件夹app/Helpers/ExtendedMigration.php 当然,它获取命名空间App\Helpers【参考方案5】:

你根本不应该使用枚举。即使使用 laravel 5.8,问题也没有解决。

感谢所有提醒的人

官方 Laravel 5.1 documentation 声明:

注意:目前不支持使用枚举列重命名表中的列。

另外,当添加可用选项enum 列声明时,您也会遇到同样的问题。

这让我得出一个结论,你应该小心使用枚举。甚至你根本不应该使用枚举。

我不能投票赞成任何用字符串替换枚举的答案。不,您需要创建一个查找表并将枚举替换为unsignedInteger 作为foreign key

工作量很大,如果没有以前的单元测试覆盖,你会很沮丧,但这是一个正确的解决方案。

你甚至可能因为正确地做这件事而被解雇,因为它花费的时间太长,但是,别担心,你会找到一份更好的工作。 :)

下面是一个例子,说明在enum 列声明中添加可用选项有多么困难

说你有这个:

Schema::create('blogs', function (Blueprint $table) 
    $table->enum('type', [BlogType::KEY_PAYMENTS]);
    $table->index(['type', 'created_at']);
...

并且您需要提供更多类型

public function up(): void

    Schema::table('blogs', function (Blueprint $table) 
        $table->dropIndex(['type', 'created_at']);
        $table->enum('type_tmp', [
            BlogType::KEY_PAYMENTS,
            BlogType::KEY_CATS,
            BlogType::KEY_DOGS,
        ])->after('type');
    );

    DB::statement('update `blogs` as te set te.`type_tmp` = te.`type` ');

    Schema::table('blogs', function (Blueprint $table) 
        $table->dropColumn('type');
    );

    Schema::table('blogs', function (Blueprint $table) 
        $table->enum('type', [
            BlogType::KEY_PAYMENTS,
            BlogType::KEY_CATS,
            BlogType::KEY_DOGS,
        ])->after('type_tmp');
    );

    DB::statement('update `blogs` as te set te.`type` = te.`type_tmp` ');

    Schema::table('blogs', function (Blueprint $table) 
        $table->dropColumn('type_tmp');
        $table->index(['type', 'created_at']);
    );

【讨论】:

【参考方案6】:

我认为解决此问题的最简单方法是在适用的情况下将映射类型添加到教义.yaml,以便将枚举视为字符串。

doctrine:
    dbal:
        #other configuration
        mapping_types:
            enum: string

【讨论】:

【参考方案7】:

您可以使用上述建议,也可以将以下代码添加到您的迁移文件中...

public function up()
    
DB::connection()->getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');

Schema::table('<YOUR_TABLE>', function (Blueprint $table) 
//YOUR CHANGES HERE
    
    

【讨论】:

在 laravel 7.x 上试过这个。仍然错误,但感谢您的想法 它适用于 8.x。不过,我有不同的情况,我正在检索给定表的架构列表 这只是上面most upvoted answer的一个副本。【参考方案8】:

Laravel:5.8、6、7、8

use Doctrine\DBAL\Types\StringType;
use Doctrine\DBAL\Types\Type;
use Illuminate\Support\Facades\DB;

    public function __construct()
    
        if (! Type::hasType('enum')) 
            Type::addType('enum', StringType::class);
        
        // For point types
        // DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('point', 'string');
        DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
    

【讨论】:

Type 类是什么? 我更新了代码:Doctrine\DBAL\Types\Type 多年前的 This answer 还包括 registerDoctrineTypeMapping() 命令本身。致电addType() 对改进该答案有何帮助? 可能我没有机会测试它。让我们知道

以上是关于Laravel 5.1 请求未知数据库类型枚举的主要内容,如果未能解决你的问题,请参考以下文章

请求 Laravel 迁移未知数据库枚举

未知数据库类型枚举请求学说

SQLSTATE [42S22]:找不到列:1054 未知列 laravel 5.1

Laravel 5.1 Request请求怎么用?

表中的更改列在postgres中具有枚举类型

Laravel 5.1使用控制器和模型消耗soap wsdl服务