Laravel 5.1 Unbekannter Datenbanktyp enum angefordert

72

Beim Ausführen von PHP Artisan Migrate wurde der folgende Fehler angezeigt

[Doctrine \ DBAL \ DBALException]
Unbekannte Datenbanktyp-Aufzählung angefordert, Doctrine \ DBAL \ Platforms \ MySqlPlatform unterstützt dies möglicherweise nicht.

So beheben Sie dieses Problem.

Code:

public function up() {
    Schema::table('blogs', function (Blueprint $table) {
        $table->string('wordpress_id')->nullable();
        $table->string('google_blog_id')->nullable()->change();
    });
}
karthick
quelle
Bitte posten Sie das Schema, das Sie migrieren möchten.
Adrenaxus
public function up () {Schema :: table ('Blogs', Funktion (Blueprint $ table) {$ table-> string ('wordpress_id') -> nullable (); $ table-> string ('google_blog_id') -> nullable () -> change ();}); }
Karthick
Enthält Ihre Tabelle eine enumSpalte?
Adrenaxus
Ja. Es hat ein Aufzählungstypfeld. In einer anderen Migration (aber diese Migration funktioniert einwandfrei) habe ich die folgende 'DB :: -Anweisung (' ALTER TABLE-Blogs MODIFY type enum ("wordpress", "blogger") NULL; ');'
Karthick
Das Umbenennen von Spalten in einer Tabelle mit einer Aufzählungsspalte wird derzeit in Laravel nicht unterstützt. Es spielt keine Rolle, ob Sie versuchen, eine andere Spalte zu ändern. Wenn die Tabelle eine enthält, enumfunktioniert sie nicht. Ich befürchte, dass Sie das irgendwie manuell ändern oder einige ziemlich hässliche Hacks oder Workarounds ausprobieren müssen.
Adrenaxus

Antworten:

104

In der offiziellen Laravel 5.1- Dokumentation heißt es:

Hinweis: Das Umbenennen von Spalten in einer Tabelle mit einer Aufzählungsspalte wird derzeit nicht unterstützt.

Es spielt keine Rolle, ob Sie versuchen, eine andere Spalte zu ändern. Wenn die Tabelle eine enum Stelle enthält, funktioniert dies nicht. Es ist ein Doctrine DBAL-Problem.

Um dieses Problem zu umgehen, können Sie entweder die Spalte löschen und eine neue hinzufügen ( Spaltendaten gehen verloren ):

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

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

oder verwenden Sie eine DB-Anweisung:

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

Quelle: https://github.com/laravel/framework/issues/1186

Adrenaxus
quelle
1
Vielen Dank für die Lösung, Drop Column ist nicht immer möglich, also sollte manuelle Änderung es tun
Ali Alwash
3
Sie brauchen die SchemaUmhüllung DB::statementnicht, wenn Sie nicht verwenden$table
Jonathan
Ach wie schade! Ich habe versucht, eine Spalte zu aktualisieren, die nicht mit der Aufzählung zusammenhängt, und dies sendet die Ausnahme. Ok, ich denke die DB :: Anweisung ist hier die beste Option. Danke.
MarkSkayff
Ich würde den zweiten Ansatz bevorzugen, da der erste die Daten beeinflussen würde, da er Spalten löschen und neu erstellen würde. Der zweite Ansatz wirkt sich jedoch nur auf die Tabellenstruktur aus.
Gayan
3
Was zum Teufel ist daran falsch, doctrine/dbaldass Sie nichts tun können, was mit einer SQL-Abfrage sehr einfach zu tun ist?
Spencer Williams
115

Es ist ein bekanntes Problem, wie in der Dokumentation zu Laravel 5.1 angegeben .

Hinweis: Das Umbenennen von Spalten in einer Tabelle mit einer enumSpalte wird derzeit nicht unterstützt.

Es passiert, wenn Sie eine enumSpalte in Ihrer Datenbanktabelle haben. Unabhängig davon, ob Sie versuchen, eine andere Spalte umzubenennen oder eine andere Spalte in zu ändern nullable, wird dieser Fehler angezeigt. Es ist ein Problem mit Doctrine\DBAL.

Eine einfache Lösung hierfür besteht darin, diese Konstruktormethode einfach in Ihre Datenbankmigrationsdatei einzufügen.

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

Dadurch werden alle ENUMSpalten zugeordnet VARCHAR(), und die Spalte akzeptiert alle Zeichenfolgen.

Dies funktionierte für mich auf Laravel 5.1 und Laravel 5.3. Ich hoffe, dass dieser Fehler bald behoben werden kann.

Dank an @ Gmatkowskis Antwort unter https://stackoverflow.com/a/32860409/1193201

Xeleon
quelle
15
Dies sollte die akzeptierte Antwort sein! Vielen Dank, dass Sie @Xeleon
Ema4rl
5
Wird dies die Typzuordnung global ändern oder nur für die Migration, in der sie angegeben ist? Und wenn es global ist, hat dies andere Nebenwirkungen? Natürlich habe ich den alten Laravel 4-Weg verwendet, der auch funktioniert ( laraveldaily.com/… ).
Bas Weitjens
3
Ich musste diese Zeile hinzufügen, AppServiceProvider::boot()damit es funktioniert.
andreshg112
Danke, das hat funktioniert. Ich bin gerade auf 6.x darauf gestoßen und sehe, dass das bekannte Problem ab sofort auf 8.x besteht
chrisan
danke, dass funktioniert hat
PHOKKINN KY
5

Eine wirklich schmutzige Lösung, die die Arbeit trotzdem erledigt

update Doctrine/DBAL/Schema/MySqlSchemaManager.php 

durch Hinzufügen dieser Zeilen direkt über Zeile 113

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

Beachten Sie, dass das direkte Aktualisieren von Herstellerdateien nicht ratsam ist, da im Falle, dass der vonder das Plugin aktualisiert, Änderungen möglicherweise überschrieben werden

Cengkuru Michael
quelle
Ich mache es, aber es funktioniert nicht. protected function _getPortableDatabaseDefinition($database) { $this->_platform->registerDoctrineTypeMapping('enum', 'string'); $type = $this->_platform->getDoctrineTypeMapping($dbType); return $database['Database']; }
andreshg112
5

Ich behebe dieses Problem, indem ich eine neue Migrationsklasse erstelle und meine Migrationen von dieser aus ausdehne. Vielleicht gibt es mehrere Möglichkeiten, es "standardisierter" zu machen, aber dies ist nur ein sehr einfacher Fall, der für unser Team perfekt funktioniert.

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

Erweitern Sie dann, wie zuvor erläutert, einfach Ihre Migration

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');
    }
}
Hector Manuel
quelle
Wo soll diese ExtendedMigration platziert werden? Ich habe den Typ bei einer normalen Migration erfolgreich direkt zur Funktion up hinzugefügt, aber ich bin gespannt, wo Sie die ExtendedMigration-Klasse
Dika
1
@Dika, Abhängig von Ihrer Art von Projekt, wenn Sie eine Bibliothek erstellen, ist es möglicherweise sinnvoll, sie in den Datenbankordner zu legen. In meinem Fall haben wir ein reguläres Laravel-Projekt und ich habe es unter einem Hilfeordner app/Helpers/ExtendedMigration.php und natürlich wird es der NamespaceApp\Helpers
Hector Manuel
5

Sie sollten enum überhaupt nicht verwenden. Selbst mit Laravel 5.8 ist das Problem nicht gelöst.

Vielen Dank an alle, die daran erinnert haben

In der offiziellen Laravel 5.1- Dokumentation heißt es:

Hinweis: Das Umbenennen von Spalten in einer Tabelle mit einer Aufzählungsspalte wird derzeit nicht unterstützt.

Und Sie werden das gleiche Problem haben , wenn verfügbare Optionen Zugabe in enumSpalte Erklärung.

Es bringt mich zu dem Schluss, dass Sie Enum mit Vorsicht verwenden sollten. oder sogar Sie sollten enum überhaupt nicht verwenden.

Ich kann keine Antwort auf dieses Angebot abgeben, Enum durch String zu ersetzen. NEIN, Sie müssen eine Nachschlagetabelle erstellen und die Aufzählung durch unsignedIntegerals ersetzenforeign key .

Es ist eine Menge Arbeit und Sie werden verärgert sein, wenn Sie dies nicht ohne vorherige Berichterstattung über Unit-Tests tun, aber dies ist eine richtige Lösung.

Möglicherweise werden Sie sogar entlassen, weil Sie dies richtig gemacht haben, weil es zu lange dauert, aber keine Sorge, Sie werden einen besseren Job finden. :) :)

Hier ist ein Beispiel dafür , wie schwierig wäre es werden Optionen Zugabe in enumSpalte Erklärung

Sagen Sie, Sie haben dies:

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

und Sie müssen mehr Typen verfügbar machen

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']);
    });
}
Jewgenij Afanasjew
quelle
3

Sie können entweder die obigen Vorschläge verwenden oder den folgenden Code zu Ihrer Migrationsdatei hinzufügen ...

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

Schema::table('<YOUR_TABLE>', function (Blueprint $table) {
//YOUR CHANGES HERE
}    
    }
Ajjay Arora
quelle
1
versuchte dies auf Laravel 7.x. immer noch Fehler, aber danke für die Idee
Dika
1
Es funktioniert für mich am 8.x. Ich habe jedoch einen anderen Fall, ich
rufe
2

Ich denke, der einfachste Weg, um dieses Problem zu beheben, ist das Hinzufügen eines Zuordnungstyps zu doctrine.yaml, falls zutreffend, damit enum als Zeichenfolge behandelt wird.

doctrine:
    dbal:
        #other configuration
        mapping_types:
            enum: string
simsek
quelle
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');
    }
William Desportes
quelle