Mengisi database dalam file migrasi Laravel

115

Saya baru mempelajari Laravel, dan memiliki file migrasi yang berfungsi membuat tabel pengguna. Saya mencoba mengisi catatan pengguna sebagai bagian dari migrasi:

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

    });
}

Tapi saya mendapatkan kesalahan berikut saat menjalankan php artisan migrate:

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

Ini jelas karena Artisan belum membuat tabel, tetapi semua dokumentasi tampaknya mengatakan bahwa ada cara menggunakan Fluent Query untuk mengisi data sebagai bagian dari migrasi.

Ada yang tahu caranya? Terima kasih!

Adam Hopkinson
sumber

Jawaban:

215

Jangan letakkan DB :: insert () di dalam Schema :: create (), karena metode create harus menyelesaikan pembuatan tabel sebelum Anda dapat memasukkan sesuatu. Coba ini sebagai gantinya:

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
sumber
5
dan bagaimana cara memasukkan banyak data?
Sahbaz
6
@ SuperMario'sYoshi saya pikir sesuatu seperti iniDB::table('users')->insert([ ['email' => '[email protected]', 'votes' => 0], ['email' => '[email protected]', 'votes' => 0] ]);
Денис
80

Saya tahu ini adalah posting lama tetapi karena muncul di pencarian google, saya pikir saya akan membagikan beberapa pengetahuan di sini. @erin-geyer menunjukkan bahwa menggabungkan migrasi dan seeder dapat membuat pusing kepala dan @justamartin membalas bahwa terkadang Anda ingin / membutuhkan data untuk diisi sebagai bagian dari penerapan Anda.

Saya akan melangkah lebih jauh dan mengatakan bahwa terkadang diinginkan untuk dapat meluncurkan perubahan data secara konsisten sehingga Anda dapat, misalnya, menerapkan ke pementasan, melihat bahwa semuanya baik-baik saja, dan kemudian menerapkan ke produksi dengan keyakinan akan hasil yang sama (dan tidak harus ingat untuk menjalankan beberapa langkah manual).

Namun, masih ada gunanya memisahkan benih dan migrasi karena keduanya terkait tetapi berbeda. Tim kami telah berkompromi dengan membuat migrasi yang disebut seeder. Ini terlihat seperti:

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

Ini memungkinkan Anda untuk mengeksekusi benih satu kali seperti migrasi. Anda juga bisa mengimplementasikan logika yang mencegah atau menambah perilaku. Sebagai contoh:

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

Ini jelas akan mengeksekusi seeder Anda secara bersyarat jika ada kurang dari 10 SomeModels. Ini berguna jika Anda ingin menyertakan seeder sebagai seeder standar yang dijalankan saat Anda memanggil artisan db:seedserta saat Anda bermigrasi sehingga Anda tidak "menggandakan". Anda juga dapat membuat seeder terbalik sehingga rollback bekerja seperti yang diharapkan, mis

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

Parameter kedua --forcediperlukan untuk mengaktifkan seeder untuk berjalan di lingkungan produksi.

darrylkuhn
sumber
2
Sejauh ini, ini adalah jawaban terbaik. Kode yang dapat dipertahankan yang memisahkan masalah!
helsont
18
Saya akan berhati-hati untuk mempertimbangkan implikasi jangka panjang dari memanggil seeder dari skrip migrasi. Skrip migrasi memiliki versi tanggal / waktu, sedangkan seeder biasanya tidak. Selama pengembangan, kebutuhan seeder sering berubah, yang mengakibatkan kemungkinan skrip migrasi berversi menjalankan seeder non-berversi - melanggar idempotensi. Dengan kata lain, menjalankan kumpulan skrip migrasi yang sama dari hari ke hari dapat memberikan hasil yang berbeda.
originalbryan
2
Sudah lama sejak saya memposting ini dan saya ingin memberikan pengalaman kami menggunakan teknik ini. Secara keseluruhan itu telah bekerja dengan baik bagi kami dan jika saya harus melakukannya lagi, saya akan melakukannya. Yang mengatakan ada satu gotcha yang harus diperhatikan. @originalbryan benar dan konsekuensinya adalah kita kadang-kadang mengalami situasi di mana migrasi berhenti ketika menjalankan DB baru karena saat migrasi dijalankan, seeder (dan model) lebih up-to-date daripada database (karena kita mungkin seed sebelum skema diperbarui sepenuhnya). Ketika itu terjadi, kami memperbarui migrasi lama untuk mengatasi masalah tersebut.
darrylkuhn
@darrylkuhn Saya mendengar bahwa memperbarui file migrasi lama bukanlah praktik yang baik - alih-alih memperbarui file lama, Anda harus membuat file migrasi baru - ini adalah "alur kerja" untuk file migrasi berdasarkan desain
Kamil Kiełczewski
2
Semua bahasa Laravel menyiratkan seeder adalah untuk data pengujian, jadi saya pikir itu harus diingat dengan desain. Penting untuk membedakan antara data yang merupakan bagian dari aplikasi vs data pengujian, dan menyertakan data yang diperlukan secara langsung dalam migrasi membuat perbedaan itu sangat jelas.
Brettins
13

Berikut adalah penjelasan yang sangat bagus tentang mengapa menggunakan Database Seeder Laravel lebih disukai daripada menggunakan Migrasi: http://laravelbook.com/laravel-database-seeding/

Meskipun, mengikuti petunjuk pada dokumentasi resmi adalah ide yang jauh lebih baik karena penerapan yang dijelaskan pada tautan di atas tampaknya tidak berfungsi dan tidak lengkap. http://laravel.com/docs/migrations#database-seeding

Erin Geyer
sumber
1
Saya setuju dengan Anda Erin. Jangan mencampur migrasi dengan data seed karena kemungkinan besar Anda ingin melakukan seed beberapa data di lingkungan pengembangan Anda tetapi tidak di lingkungan produksi.
Daniel Vigueras
18
Poin bagus, tetapi ada beberapa situasi di mana beberapa data harus ada di lingkungan produksi. Misalnya, pengguna admin default pertama harus ada sehingga pelanggan dapat masuk untuk pertama kalinya, beberapa peran otorisasi yang telah ditetapkan harus ada, beberapa data logika bisnis juga mungkin diperlukan segera. Jadi, menurut saya data wajib harus ditambahkan ke migrasi (sehingga Anda dapat naik / turun juga catatan data melalui migrasi terpisah), tetapi benih dapat dibiarkan untuk pengembangan.
JustAMartin
Catatan kecil; tautan ke penyemaian basis data sekarang: laravel.com/docs/5.3/seeding
magikMaker
3

Ini harus melakukan apa yang Anda inginkan.

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

Cara bersih lainnya untuk melakukannya adalah dengan mendefinisikan metode privat yang membuat contoh dan mempertahankan Model terkait.

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

Dengan solusi ini, bidang cap waktu akan dibuat oleh Eloquent.

EDIT: lebih baik menggunakan sistem seeder untuk membedakan pembuatan struktur database dan populasi database.

Maximilien DI DIO
sumber
Saya suka yang ini ... itu server persis apa yang perlu saya lakukan, menambahkan beberapa peran pengguna secara default saat migrasi. Perlu memastikan untuk mengimpor model atau merujuk langsung ke model tersebut $model = new App\UserRoles();, tetapi selain itu ... sempurna!
FAB
1

Saya mencoba metode penyisipan DB ini, tetapi karena tidak menggunakan model, metode ini mengabaikan sifat lamban yang saya miliki pada model. Jadi, mengingat Model untuk tabel ini ada, segera setelah dimigrasi, saya pikir model tersebut akan tersedia untuk digunakan untuk memasukkan data. Dan saya datang dengan ini:

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

Ini berfungsi dengan benar, dan juga memperhitungkan sifat lamban pada Model saya untuk secara otomatis menghasilkan siput untuk entri ini, dan menggunakan cap waktu juga. NB. Tidak perlu menambahkan ID, namun, saya menginginkan ID khusus untuk kategori saya dalam contoh ini. Diuji bekerja pada Laravel 5.8

Andrew Arscott
sumber
0

Jika Anda sudah mengisi kolom dan telah menambahkan yang baru atau Anda ingin mengisi kolom lama dengan nilai tiruan baru, lakukan ini:

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