Auffüllen einer Datenbank in einer Laravel-Migrationsdatei

115

Ich lerne gerade Laravel und habe eine funktionierende Migrationsdatei, die eine Benutzertabelle erstellt. Ich versuche, einen Benutzerdatensatz im Rahmen der Migration zu füllen:

public function up()
{
    Schema::create('users', function($table){

        $table->increments('id');
        $table->string('email', 255);
        $table->string('password', 64);
        $table->boolean('verified');
        $table->string('token', 255);
        $table->timestamps();

        DB::table('users')->insert(
            array(
                'email' => '[email protected]',
                'verified' => true
            )
        );

    });
}

Beim Ausführen wird jedoch der folgende Fehler angezeigt php artisan migrate:

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'vantage.users' doesn't exist

Dies liegt offensichtlich daran, dass Artisan die Tabelle noch nicht erstellt hat, aber die gesamte Dokumentation scheint zu sagen, dass es eine Möglichkeit gibt, Fluent Query zum Auffüllen von Daten im Rahmen einer Migration zu verwenden.

Weiß jemand wie? Vielen Dank!

Adam Hopkinson
quelle

Antworten:

215

Fügen Sie DB :: insert () nicht in Schema :: create () ein, da die create-Methode die Erstellung der Tabelle abschließen muss, bevor Sie Inhalte einfügen können. Versuchen Sie stattdessen Folgendes:

public function up()
{
    // Create the table
    Schema::create('users', function($table){
        $table->increments('id');
        $table->string('email', 255);
        $table->string('password', 64);
        $table->boolean('verified');
        $table->string('token', 255);
        $table->timestamps();
    });

    // Insert some stuff
    DB::table('users')->insert(
        array(
            'email' => '[email protected]',
            'verified' => true
        )
    );
}
BenjaminRH
quelle
5
und wie man mehrere Daten einfügt?
Sahbaz
6
@ SuperMario'sYoshi ich denke so etwasDB::table('users')->insert([ ['email' => '[email protected]', 'votes' => 0], ['email' => '[email protected]', 'votes' => 0] ]);
Денис
80

Ich weiß, dass dies ein alter Beitrag ist, aber da er in einer Google-Suche auftaucht, dachte ich, ich würde hier etwas Wissen teilen. @ erin-geyer wies darauf hin, dass das Mischen von Migrationen und Seedern Kopfschmerzen verursachen kann, und @justamartin konterte, dass manchmal Daten im Rahmen Ihrer Bereitstellung ausgefüllt werden sollen / müssen.

Ich würde noch einen Schritt weiter gehen und sagen, dass es manchmal wünschenswert ist, Datenänderungen konsistent einführen zu können, damit Sie beispielsweise für Staging bereitstellen, sicherstellen können, dass alles in Ordnung ist, und dann mit dem Vertrauen auf dieselben Ergebnisse für die Produktion bereitstellen können (und müssen nicht daran denken, einen manuellen Schritt auszuführen).

Es ist jedoch immer noch sinnvoll, das Saatgut und die Migration zu trennen, da dies zwei verwandte, aber unterschiedliche Anliegen sind. Unser Team hat Kompromisse geschlossen, indem es Migrationen erstellt hat, die Sämaschinen nennen. Das sieht so aus:

public function up()
{
    Artisan::call( 'db:seed', [
        '--class' => 'SomeSeeder',
        '--force' => true ]
    );
}

Auf diese Weise können Sie einen Startwert wie bei einer Migration einmal ausführen. Sie können auch eine Logik implementieren, die das Verhalten verhindert oder erweitert. Beispielsweise:

public function up()
{
    if ( SomeModel::count() < 10 )
    {
        Artisan::call( 'db:seed', [
            '--class' => 'SomeSeeder',
            '--force' => true ]
        );
    }
}

Dies würde Ihren Seeder natürlich bedingt ausführen, wenn weniger als 10 SomeModels vorhanden sind. Dies ist nützlich, wenn Sie den Seeder als Standard-Seeder einschließen möchten, der sowohl beim Aufrufen artisan db:seedals auch bei der Migration ausgeführt wird, damit Sie nicht "verdoppeln". Sie können auch eine Rückwärtssämaschine erstellen, damit Rollbacks wie erwartet funktionieren, z

public function down()
{
    Artisan::call( 'db:seed', [
        '--class' => 'ReverseSomeSeeder',
        '--force' => true ]
    );
}

Der zweite Parameter --forceist erforderlich, damit Seeder in einer Produktionsumgebung ausgeführt werden kann.

darrylkuhn
quelle
2
Dies ist bei weitem die beste Antwort. Wartbarer Code, der Bedenken trennt!
Helsont
18
Ich würde die langfristigen Auswirkungen des Aufrufs von Seedern aus Migrationsskripten berücksichtigen. Die Migrationsskripte sind mit Datum / Uhrzeit versioniert, Seeders normalerweise nicht. Während der Entwicklung ändern sich die Anforderungen von Seedern häufig, was dazu führt, dass versionierte Migrationsskripte nicht versionierte Seeders ausführen - was die Idempotenz bricht. Mit anderen Worten, wenn Sie jeden Tag denselben Satz von Migrationsskripten ausführen, kann dies zu unterschiedlichen Ergebnissen führen.
Originalbryan
2
Es ist schon eine Weile her, dass ich dies gepostet habe und ich wollte unsere Erfahrung mit dieser Technik vermitteln. Insgesamt hat es bei uns gut funktioniert und wenn ich es noch einmal machen müsste, würde ich es tun. Das heißt, es gibt eine Gotcha zu beachten. @originalbryan ist genau richtig und die Folge ist, dass wir gelegentlich auf Situationen stoßen, in denen Migrationen beim Hochfahren einer neuen Datenbank unterbrochen werden, da der Seeder (und das Modell) während der Ausführung der Migrationen aktueller sind als die Datenbank (da wir möglicherweise Seed verwenden) bevor das Schema vollständig aktualisiert wird). In diesem Fall aktualisieren wir die alte Migration, um das Problem zu beheben.
Darrylkuhn
@darrylkuhn Ich höre, dass es nicht empfehlenswert ist, alte Migrationsdateien zu aktualisieren - anstatt alte Dateien zu aktualisieren, sollten Sie eine neue Migrationsdatei erstellen - dies ist ein "Workflow" für Migrationsdateien von Entwurf
Kamil Kiełczewski
2
Die gesamte Sprache von Laravel impliziert, dass eine Sämaschine für Testdaten vorgesehen ist. Ich denke, dies sollte beim Design berücksichtigt werden. Es ist wichtig, zwischen Daten, die Teil der App sind, und Testdaten zu unterscheiden, und die Einbeziehung der erforderlichen Daten direkt in eine Migration macht diese Unterscheidung sehr deutlich.
Brettins
12

Hier ist eine sehr gute Erklärung, warum die Verwendung von Laravels Database Seeder der Verwendung von Migrationen vorzuziehen ist: http://laravelbook.com/laravel-database-seeding/

Das Befolgen der Anweisungen in der offiziellen Dokumentation ist jedoch eine viel bessere Idee, da die unter dem obigen Link beschriebene Implementierung nicht zu funktionieren scheint und unvollständig ist. http://laravel.com/docs/migrations#database-seeding

Erin Geyer
quelle
1
Ich stimme dir zu, Erin. Mischen Sie Migrationen nicht mit Seed-Daten, da Sie höchstwahrscheinlich einige Daten in Ihrer Entwicklungsumgebung, aber nicht in Ihrer Produktionsumgebung säen möchten.
Daniel Vigueras
18
Guter Punkt, aber es gibt Situationen, in denen einige Daten in der Produktionsumgebung vorhanden sein müssen. Beispielsweise muss der allererste Standard-Administratorbenutzer vorhanden sein, damit sich der Kunde zum ersten Mal anmelden kann. Einige voreingestellte Berechtigungsrollen müssen vorhanden sein. Einige Geschäftslogikdaten sind möglicherweise auch sofort erforderlich. Daher denke ich, dass Migrationen obligatorische Daten hinzugefügt werden sollten (damit Sie auch Datensätze durch separate Migrationen hoch- / runterfahren können), aber Samen können für die Entwicklung übrig bleiben.
JustAMartin
Eine kleine Notiz; Der Link zum Datenbank-Seeding lautet jetzt: laravel.com/docs/5.3/seeding
magikMaker
3

Dies sollte tun, was Sie wollen.

public function up()
{
    DB::table('user')->insert(array('username'=>'dude', 'password'=>'z19pers!'));
}
string28
quelle
1

Eine andere saubere Möglichkeit besteht darin, eine private Methode zu definieren, mit der eine Instanz erstellt und das betreffende Modell beibehalten wird.

public function up()
{
    Schema::create('roles', function (Blueprint $table) {
        $table->increments('id');
        $table->string('label', 256);
        $table->timestamps();
        $table->softDeletes();
    });

    $this->postCreate('admin', 'user');
}

private function postCreate(string ...$roles)  {
    foreach ($roles as $role) {
        $model = new Role();
        $model->setAttribute('label', $role);
        $model->save();
    }
}

Mit dieser Lösung werden Zeitstempelfelder von Eloquent generiert.

BEARBEITEN: Es ist besser, das Seeder-System zu verwenden, um die Generierung der Datenbankstruktur und die Datenbankpopulation zu unterscheiden.

Maximilien DI DIO
quelle
Ich mag dieses ... es dient genau dem, was ich tun musste, und fügt bei der Migration standardmäßig einige Benutzerrollen hinzu. Sie müssen sicherstellen, dass Sie das Modell entweder importieren oder direkt darauf verweisen $model = new App\UserRoles();, aber ansonsten ... perfekt!
FAB
1

Ich habe diese DB-Einfügemethode ausprobiert, aber da sie das Modell nicht verwendet, hat sie eine träge Eigenschaft ignoriert, die ich für das Modell hatte. Da das Modell für diese Tabelle vorhanden ist, dachte ich, dass das Modell zum Einfügen von Daten verfügbar sein würde, sobald es migriert ist. Und ich habe mir das ausgedacht:

public function up() {
        Schema::create('parent_categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->string('slug');
            $table->timestamps();
        });
        ParentCategory::create(
            [
                'id' => 1,
                'name' => 'Occasions',
            ],
        );
    }

Dies funktionierte korrekt und berücksichtigte auch die schleppbare Eigenschaft meines Modells, um automatisch eine Schnecke für diesen Eintrag zu generieren, und verwendet auch die Zeitstempel. NB. Das Hinzufügen der ID war nicht erforderlich. In diesem Beispiel wollte ich jedoch bestimmte IDs für meine Kategorien. Getestete Arbeit an Laravel 5.8

Andrew Arscott
quelle
0

Wenn Sie bereits Spalten gefüllt und neue hinzugefügt haben oder alte Spalten mit neuen Scheinwerten füllen möchten, gehen Sie folgendermaßen vor:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
CodeToLife
quelle