การเติมฐานข้อมูลในไฟล์การย้าย Laravel


115

ฉันเพิ่งเรียนรู้ Laravel และมีไฟล์การย้ายข้อมูลที่ใช้งานได้ซึ่งสร้างตารางผู้ใช้ ฉันกำลังพยายามเติมข้อมูลบันทึกผู้ใช้เป็นส่วนหนึ่งของการย้ายข้อมูล:

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

    });
}

แต่ฉันได้รับข้อผิดพลาดต่อไปนี้เมื่อทำงานphp artisan migrate:

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

เห็นได้ชัดว่าเป็นเพราะ Artisan ยังไม่ได้สร้างตาราง แต่เอกสารทั้งหมดดูเหมือนจะบอกว่ามีวิธีการใช้ Fluent Query เพื่อเติมข้อมูลเป็นส่วนหนึ่งของการย้ายข้อมูล

ใครรู้วิธีบ้าง ขอบคุณ!

คำตอบ:


215

อย่าใส่ DB :: insert () ไว้ใน Schema :: create () เนื่องจากเมธอด create ต้องทำให้ตารางเสร็จสิ้นก่อนจึงจะสามารถแทรกสิ่งต่างๆ ลองสิ่งนี้แทน:

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
และวิธีการแทรกข้อมูลหลาย?
Sahbaz

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

80

ฉันรู้ว่านี่เป็นโพสต์เก่า แต่เนื่องจากมันเกิดขึ้นในการค้นหาโดย Google ฉันคิดว่าฉันจะแบ่งปันความรู้ที่นี่ @ erin-geyer ชี้ให้เห็นว่าการโยกย้ายแบบผสมผสานและผู้เริ่มต้นสามารถสร้างความปวดหัวและ @justamartin ตอบโต้ว่าบางครั้งคุณต้องการ / ต้องการข้อมูลเพื่อบรรจุเป็นส่วนหนึ่งของการปรับใช้ของคุณ

ฉันจะก้าวไปอีกขั้นและบอกว่าบางครั้งก็เป็นที่พึงปรารถนาที่จะสามารถนำการเปลี่ยนแปลงข้อมูลออกมาใช้ได้อย่างสม่ำเสมอตัวอย่างเช่นคุณสามารถปรับใช้กับการจัดเตรียมดูว่าทุกอย่างเรียบร้อยดีแล้วจึงนำไปใช้ในการผลิตด้วยความมั่นใจในผลลัพธ์เดียวกัน (และไม่ต้องจำไว้ว่าต้องใช้ขั้นตอนด้วยตนเอง)

อย่างไรก็ตามยังคงมีคุณค่าในการแยกเมล็ดพันธุ์ออกจากกันและการย้ายถิ่นเนื่องจากสิ่งเหล่านี้เกี่ยวข้องกัน แต่มีข้อกังวลที่แตกต่างกัน ทีมของเราได้ทำลายโดยการสร้างการย้ายข้อมูลที่เรียกว่า seeders ดูเหมือนว่า:

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

สิ่งนี้ช่วยให้คุณดำเนินการเมล็ดพันธุ์ได้ครั้งเดียวเช่นเดียวกับการย้ายข้อมูล คุณยังสามารถใช้ตรรกะที่ป้องกันหรือเพิ่มพฤติกรรม ตัวอย่างเช่น:

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

เห็นได้ชัดว่าสิ่งนี้จะดำเนินการกับ seeder ของคุณอย่างมีเงื่อนไขหากมี SomeModels น้อยกว่า 10 ตัว สิ่งนี้มีประโยชน์หากคุณต้องการรวม seeder เป็น seeder มาตรฐานที่ดำเนินการเมื่อคุณเรียกartisan db:seedและเมื่อคุณย้ายข้อมูลเพื่อที่คุณจะได้ไม่ "เพิ่มขึ้นสองเท่า" คุณยังสามารถสร้างตัวเริ่มต้นย้อนกลับเพื่อให้การย้อนกลับทำงานได้ตามที่คาดไว้เช่น

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

พารามิเตอร์ที่สอง--forceจำเป็นเพื่อเปิดใช้งานเพื่อ seeder เพื่อรันในสภาวะแวดล้อมการผลิต


2
นี่เป็นคำตอบที่ดีที่สุด รหัสบำรุงรักษาที่แยกความกังวล!
helsont

18
ฉันจะระมัดระวังในการพิจารณาผลกระทบระยะยาวของการเรียก seeders จากสคริปต์การย้ายข้อมูล สคริปต์การย้ายข้อมูลเป็นเวอร์ชันวันที่ / เวลาในขณะที่ตัวเริ่มต้นมักจะไม่ใช่ ในระหว่างการพัฒนาความต้องการของ seeder มักจะเปลี่ยนไปส่งผลให้สคริปต์การโอนย้ายเวอร์ชันที่เป็นเวอร์ชันรันที่ไม่ใช่เวอร์ชันเริ่มต้นใช้งานได้ซึ่งจะทำลาย idempotency กล่าวอีกนัยหนึ่งการเรียกใช้สคริปต์การย้ายชุดเดียวกันในแต่ละวันอาจให้ผลลัพธ์ที่แตกต่างกัน
originalbryan

2
เป็นเวลานานแล้วที่ฉันโพสต์สิ่งนี้และฉันต้องการให้ประสบการณ์ของเราโดยใช้เทคนิคนี้ โดยรวมแล้วมันทำงานได้ดีสำหรับเราและถ้าฉันต้องทำอีกครั้งฉันจะทำ ที่กล่าวว่ามี gotcha หนึ่งที่ต้องระวัง @originalbryan นั้นถูกต้องและผลที่ตามมาคือบางครั้งเราพบในสถานการณ์ที่การย้ายข้อมูลหยุดชะงักเมื่อหมุนฐานข้อมูลใหม่เนื่องจากเมื่อการย้ายข้อมูลเรียกใช้ seeder (และโมเดล) จะทันสมัยกว่าฐานข้อมูล (เนื่องจากเราอาจ seed ก่อนที่สคีมาจะได้รับการอัปเดตอย่างสมบูรณ์) เมื่อเป็นเช่นนั้นเราจะอัปเดตการย้ายข้อมูลเดิมเพื่อแก้ไขปัญหา
darrylkuhn

@darrylkuhn ฉันได้ยินมาว่าการอัปเดตไฟล์การย้ายข้อมูลเก่าไม่ใช่แนวทางปฏิบัติที่ดี - แทนที่จะอัปเดตไฟล์เก่าคุณควรสร้างไฟล์การย้ายข้อมูลใหม่ - นี่คือ "ขั้นตอนการทำงาน" สำหรับไฟล์การย้ายข้อมูลตามการออกแบบ
Kamil Kiełczewski

2
ภาษาทั้งหมดของ Laravel มีความหมายว่า seeder มีไว้สำหรับข้อมูลทดสอบดังนั้นฉันคิดว่าควรคำนึงถึงการออกแบบ สิ่งสำคัญคือต้องแยกความแตกต่างระหว่างข้อมูลที่เป็นส่วนหนึ่งของข้อมูลแอปเทียบกับข้อมูลทดสอบและการรวมข้อมูลที่จำเป็นโดยตรงในการย้ายข้อมูลทำให้ความแตกต่างนั้นชัดเจนมาก
Brettins

13

นี่คือคำอธิบายที่ดีมากว่าทำไมการใช้ Database Seeder ของ Laravel จึงเป็นที่นิยมในการใช้ Migrations: http://laravelbook.com/laravel-database-seeding/

แม้ว่าการปฏิบัติตามคำแนะนำในเอกสารอย่างเป็นทางการจะเป็นแนวคิดที่ดีกว่ามากเนื่องจากการใช้งานที่อธิบายไว้ในลิงก์ด้านบนดูเหมือนจะไม่ได้ผลและไม่สมบูรณ์ http://laravel.com/docs/migrations#database-seeding


1
ฉันเห็นด้วยกับคุณ Erin อย่าผสมผสานการย้ายข้อมูลกับข้อมูลเมล็ดพันธุ์เนื่องจากมีโอกาสสูงที่คุณจะต้องการรวบรวมข้อมูลบางส่วนในสภาพแวดล้อมการพัฒนาของคุณ แต่ไม่ได้อยู่ในสภาพแวดล้อมการผลิตของคุณ
Daniel Vigueras

18
จุดดี แต่มีบางสถานการณ์ที่ข้อมูลบางอย่างต้องมีอยู่ในสภาพแวดล้อมการผลิต ตัวอย่างเช่นต้องมีผู้ใช้ผู้ดูแลระบบเริ่มต้นรายแรกเพื่อให้ลูกค้าสามารถเข้าสู่ระบบได้เป็นครั้งแรกต้องมีบทบาทการอนุญาตที่ตั้งไว้ล่วงหน้าบางอย่างอาจจำเป็นต้องใช้ข้อมูลตรรกะทางธุรกิจในทันที ดังนั้นฉันคิดว่าควรเพิ่มข้อมูลที่จำเป็นในการย้ายข้อมูล (เพื่อให้คุณสามารถขึ้น / ลงบันทึกข้อมูลผ่านการย้ายข้อมูลที่แยกจากกันได้) แต่เมล็ดพันธุ์สามารถทิ้งไว้สำหรับการพัฒนาได้
JustAMartin

บันทึกเล็ก ๆ ; ลิงก์ไปยังฐานข้อมูล seeding คือlaravel.com/docs/5.3/seeding
magikMaker

3

สิ่งนี้ควรทำในสิ่งที่คุณต้องการ

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

1

อีกวิธีหนึ่งที่ทำได้อย่างชัดเจนคือการกำหนดวิธีการส่วนตัวที่สร้างอินสแตนซ์และยังคงมีโมเดลที่เกี่ยวข้อง

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

ด้วยวิธีนี้ Eloquent จะสร้างฟิลด์การประทับเวลา

แก้ไข: ควรใช้ระบบ seeder เพื่อแยกการสร้างโครงสร้างฐานข้อมูลและประชากรฐานข้อมูล


ฉันชอบอันนี้ ... มันเซิร์ฟเวอร์ตรงกับสิ่งที่ฉันต้องทำเพิ่มบทบาทผู้ใช้สองสามอย่างตามค่าเริ่มต้นในการโยกย้าย ต้องแน่ใจว่าได้นำเข้าโมเดลหรืออ้างอิงโดยตรง$model = new App\UserRoles();แต่นอกเหนือจากนั้น ... สมบูรณ์แบบ!
FAB

1

ฉันลองใช้วิธีการแทรก DB นี้ แต่เนื่องจากไม่ได้ใช้แบบจำลองจึงไม่สนใจลักษณะที่เอียงได้ที่ฉันมีในแบบจำลอง ดังนั้นเนื่องจากโมเดลสำหรับตารางนี้มีอยู่ทันทีที่ย้ายข้อมูลฉันจึงคิดว่าโมเดลจะพร้อมใช้งานเพื่อแทรกข้อมูล และฉันคิดสิ่งนี้:

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

สิ่งนี้ทำงานได้อย่างถูกต้องและยังคำนึงถึงลักษณะที่ไม่สามารถทำได้ในโมเดลของฉันเพื่อสร้างกระสุนสำหรับรายการนี้โดยอัตโนมัติและใช้การประทับเวลาด้วย NB. การเพิ่ม ID นั้นไม่จำเป็น แต่ฉันต้องการ ID เฉพาะสำหรับหมวดหมู่ของฉันในตัวอย่างนี้ ทดสอบการทำงานบน Laravel 5.8


0

หากคุณได้เติมคอลัมน์แล้วและได้เพิ่มคอลัมน์ใหม่หรือคุณต้องการกรอกคอลัมน์เก่าด้วยค่าจำลองใหม่ให้ทำดังนี้:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.