Popolamento di un database in un file di migrazione Laravel


115

Sto solo imparando Laravel e ho un file di migrazione funzionante che crea una tabella utenti. Sto cercando di popolare un record utente come parte della migrazione:

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' => 'name@domain.com',
                'verified' => true
            )
        );

    });
}

Ma ricevo il seguente errore durante l'esecuzione php artisan migrate:

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

Questo è ovviamente perché Artisan non ha ancora creato la tabella, ma tutta la documentazione sembra dire che esiste un modo per utilizzare Fluent Query per popolare i dati come parte di una migrazione.

Qualcuno sa come? Grazie!

Risposte:


215

Non mettere DB :: insert () all'interno di Schema :: create (), perché il metodo create deve finire di creare la tabella prima che tu possa inserire cose. Prova questo invece:

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' => 'name@domain.com',
            'verified' => true
        )
    );
}

5
e come inserire più dati?
Sahbaz

6
@ SuperMario'sYoshi penso che qualcosa del genereDB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]);
Денис

80

So che questo è un vecchio post, ma dal momento che viene visualizzato in una ricerca su Google, ho pensato di condividere alcune conoscenze qui. @ erin-geyer ha sottolineato che la combinazione di migrazioni e seeders può creare mal di testa e @justamartin ha ribattuto che a volte si desidera / è necessario che i dati vengano popolati come parte della distribuzione.

Vorrei fare un ulteriore passo avanti e dire che a volte è desiderabile essere in grado di implementare le modifiche ai dati in modo coerente in modo da poter, ad esempio, distribuire allo staging, vedere che tutto va bene e quindi distribuire alla produzione con la certezza degli stessi risultati (e non devi ricordarti di eseguire alcuni passaggi manuali).

Tuttavia, c'è ancora valore nel separare il seme e la migrazione poiché si tratta di due preoccupazioni correlate ma distinte. Il nostro team è sceso a compromessi creando migrazioni che chiamano seeders. Questo sembra:

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

Ciò ti consente di eseguire un seme una volta proprio come una migrazione. È inoltre possibile implementare la logica che impedisce o aumenta il comportamento. Per esempio:

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

Questo ovviamente eseguirà la seminatrice in modo condizionale se ci sono meno di 10 SomeModels. Ciò è utile se si desidera includere la seminatrice come seminatrice standard che viene eseguita sia quando si chiama artisan db:seedche quando si migra, in modo da non "raddoppiare". Puoi anche creare una seminatrice inversa in modo che i rollback funzionino come previsto, ad es

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

Il secondo parametro --forceè necessario per consentire alla seminatrice di funzionare in un ambiente di produzione.


2
Questa è di gran lunga la migliore risposta. Codice gestibile che separa le preoccupazioni!
helsont

18
Farei attenzione a considerare le implicazioni a lungo termine della chiamata di seeder dagli script di migrazione. Gli script di migrazione sono dotati di versione data / ora, mentre i seeders in genere non lo sono. Durante lo sviluppo, le esigenze del seeder cambiano spesso, con la possibilità che script di migrazione con versione eseguano seeders senza versione, interrompendo l'idempotenza. In altre parole, l'esecuzione dello stesso set di script di migrazione di giorno in giorno potrebbe produrre risultati diversi.
originalbryan

2
È passato un po 'di tempo da quando ho pubblicato questo e volevo fornire la nostra esperienza utilizzando questa tecnica. Nel complesso ha funzionato bene per noi e se dovessi farlo di nuovo lo farei. Detto questo, c'è un trucco di cui essere a conoscenza. @originalbryan ha esattamente ragione e la conseguenza è che occasionalmente ci imbattiamo in situazioni in cui le migrazioni si interrompono quando si avvia un nuovo DB perché durante l'esecuzione delle migrazioni la seminatrice (e il modello) sono più aggiornati del database (poiché prima che lo schema sia completamente aggiornato). Quando ciò accade, aggiorniamo la vecchia migrazione per risolvere il problema.
darrylkuhn

@darrylkuhn Ho sentito che non è buona norma aggiornare i vecchi file di migrazione - invece di aggiornare i vecchi file, dovresti creare un nuovo file di migrazione - questo è "flusso di lavoro" per i file di migrazione in base alla progettazione
Kamil Kiełczewski

2
Tutto il linguaggio di Laravel implica che una seminatrice sia per i dati di test, quindi penso che dovrebbe essere tenuto a mente con il design. È importante distinguere tra i dati che fanno parte dell'app rispetto ai dati di test e l'inclusione dei dati richiesti direttamente in una migrazione rende questa distinzione molto chiara.
Brettins,

13

Ecco un'ottima spiegazione del motivo per cui è preferibile utilizzare Database Seeder di Laravel rispetto a Migrations: http://laravelbook.com/laravel-database-seeding/

Tuttavia, seguire le istruzioni sulla documentazione ufficiale è un'idea molto migliore perché l'implementazione descritta al collegamento sopra non sembra funzionare ed è incompleta. http://laravel.com/docs/migrations#database-seeding


1
Sono d'accordo con te Erin. Non mischiare le migrazioni con i dati di inizializzazione perché è molto probabile che desideri eseguire il seeding di alcuni dati nel tuo ambiente di sviluppo ma non nell'ambiente di produzione.
Daniel Vigueras

18
Buon punto, ma ci sono alcune situazioni in cui alcuni dati devono esistere nell'ambiente di produzione. Ad esempio, il primo utente amministratore predefinito deve esistere in modo che il cliente possa accedere per la prima volta, devono esistere alcuni ruoli di autorizzazione preimpostati, alcuni dati di logica aziendale potrebbero anche essere richiesti immediatamente. Pertanto, penso che i dati obbligatori dovrebbero essere aggiunti alle migrazioni (in modo da poter aumentare / diminuire anche i record di dati attraverso migrazioni separate), ma i semi possono essere lasciati per lo sviluppo.
JustAMartin

Una piccola nota; il collegamento al seeding del database è ora: laravel.com/docs/5.3/seeding
magikMaker

3

Questo dovrebbe fare quello che vuoi.

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

1

Un altro modo pulito per farlo è definire un metodo privato che crei istanze e persistano nel modello interessato.

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

Con questa soluzione, i campi dei timestamp verranno generati da Eloquent.

MODIFICA: è meglio utilizzare il sistema di seminatrici per distinguere la generazione della struttura del database e la popolazione del database.


Mi piace questo ... server esattamente quello che dovevo fare, aggiungere alcuni ruoli utente per impostazione predefinita durante la migrazione. Devi assicurarti di importare il modello o di fare riferimento direttamente ad esso $model = new App\UserRoles();, ma a parte questo ... perfetto!
FAB

1

Ho provato questo metodo di inserimento DB, ma poiché non utilizza il modello, ha ignorato un tratto sluggable che avevo sul modello. Quindi, dato che il modello per questa tabella esiste, non appena è migrato, ho pensato che il modello sarebbe stato disponibile per l'inserimento dei dati. E mi è venuto in mente questo:

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

Questo ha funzionato correttamente e ha anche preso in considerazione il tratto sluggable sul mio modello per generare automaticamente uno slug per questa voce e utilizza anche i timestamp. NB. L'aggiunta dell'ID non era necessaria, tuttavia, in questo esempio volevo ID specifici per le mie categorie. Testato lavorando su Laravel 5.8


0

Se hai già riempito le colonne e ne hai aggiunta una nuova o vuoi riempire la vecchia colonna con nuovi valori fittizi, fai questo:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.