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


72

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

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

请发布您要迁移的架构。
肾上腺素

公共功能up(){Schema :: table('blogs',function(Blueprint $ table){$ table-> string('wordpress_id')-> nullable(); $ table-> string('google_blog_id')-> nullable()-> change();}); }
karthick

您的表格是否包含一enum列?
Adrenaxus

是的。它有一个枚举类型字段。在另一个迁移中(但此迁移工作正常),我有以下'DB :: statement('ALTER TABLE blogs MODIFY type enum(“ wordpress”,“ blogger”)NULL;');'
karthick

Laravel当前不支持使用enum列重命名表中的列。尝试更改另一列都没有关系。如果表格中包含enum,它将无法正常工作。恐怕您将不得不以某种方式手动更改它,或者尝试一些相当丑陋的hack或解决方法。
肾上腺素

Answers:


104

Laravel 5.1官方文档指出:

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

您是否要更改另一列都没有关系,如果表中包含enum 任何无法使用的地方。这是一个原则DBAL问题。

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

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

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

或使用数据库语句:

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


1
感谢您的解决方案,下拉列并非总是可行的,因此应该手动更改
Ali Alwash

3
如果您不使用SchemaDB::statement则不需要环绕$table
Jonathan

真可惜!我正在尝试更新与枚举无关的列,这正在发送异常。好的,我想这里的DB :: statement是最好的选择。谢谢。
MarkSkayff'17年

我更喜欢第二种方法,因为第一种方法会影响数据,因为它会删除并重新创建列。但是第二种方法只会影响表结构。
加扬

3
doctrine/dbal它们不能让您执行使用SQL查询非常容易完成的操作,这到底有什么错?
斯宾塞·威廉姆斯

115

如Laravel 5.1文档所述,这是一个已知问题。

注意:目前不支持使用enum重命名表中的

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

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

public function __construct()
{
    DB::getDoctrineSchemaManager()->getDatabasePlatform()->registerDoctrineTypeMapping('enum', 'string');
}

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

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

感谢@Gmatkowski在 https://stackoverflow.com/a/32860409/1193201上的回答


15
这应该是公认的答案!谢谢@Xeleon
Ema4rl

5
这会全局更改类型映射,还是仅针对指定的迁移类型?如果是全球性的,这还会有其他副作用吗?可以肯定的是,我使用了旧的Laravel 4方法,该方法也可以正常工作(laraveldaily.com/…)。
巴斯·魏特延斯

3
我必须添加该行以AppServiceProvider::boot()使其起作用。
andreshg112 '18

谢谢你的工作。我刚刚在6.x上遇到了这个问题,并且我知道已知的问题到目前为止仍然存在8.x
chrisan

感谢您的工作
PHOKKINN KY

5

一个真正的肮脏的解决方案,那就是完成工作

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']; }
andreshg112 '18

5

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

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

1
@Dika,根据您的项目类型,如果您要构建一个库,将其放入数据库文件夹可能很有意义,就我而言,我们有一个常规的L​​aravel项目,我将其放在helpers文件夹下 app/Helpers/ExtendedMigration.php ,当然,命名空间App\Helpers
Hector Manuel

5

您根本不应该使用枚举。即使使用laravel 5.8,问题也无法解决。

感谢所有提醒我的人

Laravel 5.1官方文档指出:

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

另外,将可用选项添加enum列声明中。

这使我得出一个结论,您应谨慎使用枚举。甚至根本不应该使用枚举。

我无法投票通过字符串替换枚举的任何答案。不,您需要创建一个查找表并将enum替换unsignedIntegerforeign 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']);
    });
}

3

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

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

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

1
在laravel 7.x上尝试了这个。仍然是错误,但感谢您的想法
Dika

1
它在8.x上对我有效。但是,我有另一种情况,我正在检索给定表的模式列表
Norgul

2

我认为解决此问题的最简单方法是在doctrine.yaml中添加一个映射类型(如果适用),以便将枚举视为字符串。

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

0

Laravel:5.8

use Doctrine\DBAL\Types\StringType;
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');
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.