Đưa cơ sở dữ liệu vào tệp di chuyển Laravel


115

Tôi chỉ mới học Laravel và có một tệp di chuyển đang hoạt động tạo bảng người dùng. Tôi đang cố gắng điền bản ghi người dùng như một phần của quá trình di chuyển:

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

    });
}

Nhưng tôi gặp lỗi sau khi chạy php artisan migrate:

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

Điều này rõ ràng là do Artisan chưa tạo bảng, nhưng tất cả các tài liệu có vẻ như nói rằng có một cách sử dụng Fluent Query để điền dữ liệu như một phần của quá trình di chuyển.

Bất cứ ai biết làm thế nào? Cảm ơn!

Câu trả lời:


215

Không đặt DB :: insert () bên trong Schema :: create (), vì phương thức create phải hoàn thành việc tạo bảng trước khi bạn có thể chèn nội dung. Hãy thử cái này thay thế:

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
và cách chèn nhiều dữ liệu?
Sahbaz

6
@ SuperMarioYoshi tôi nghĩ điều gì đó như thế nàyDB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]);
Денис

80

Tôi biết đây là một bài viết cũ nhưng vì nó xuất hiện trong một tìm kiếm trên google, tôi nghĩ rằng tôi sẽ chia sẻ một số kiến ​​thức ở đây. @ erin-geyer đã chỉ ra rằng việc kết hợp di chuyển và trình gieo hạt có thể gây đau đầu và @justamartin phản bác rằng đôi khi bạn muốn / cần dữ liệu được điền như một phần trong quá trình triển khai của mình.

Tôi muốn tiến thêm một bước nữa và nói rằng đôi khi mong muốn có thể triển khai các thay đổi dữ liệu một cách nhất quán để chẳng hạn như bạn có thể triển khai theo giai đoạn, thấy rằng tất cả đều ổn và sau đó triển khai sản xuất với kết quả tương tự (và không phải nhớ chạy một số bước thủ công).

Tuy nhiên, vẫn có giá trị trong việc tách hạt giống và di cư vì đó là hai mối quan tâm liên quan nhưng khác nhau. Nhóm của chúng tôi đã xâm nhập bằng cách tạo ra các di chuyển gọi là seeder. Điều này trông giống như:

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

Điều này cho phép bạn thực thi một lần seed giống như một lần di chuyển. Bạn cũng có thể triển khai logic ngăn chặn hoặc tăng cường hành vi. Ví dụ:

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

Điều này rõ ràng sẽ thực thi trình gieo hạt của bạn có điều kiện nếu có ít hơn 10 SomeModels. Điều này hữu ích nếu bạn muốn bao gồm trình tạo hạt giống như một trình tạo hạt tiêu chuẩn được thực thi khi bạn gọiartisan db:seed cũng như khi bạn di chuyển để bạn không bị "nhân đôi". Bạn cũng có thể tạo một trình gieo hạt ngược để quá trình khôi phục hoạt động như mong đợi, ví dụ:

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

Tham số thứ hai --forcelà bắt buộc để cho phép seeder chạy trong môi trường sản xuất.


2
Đây là câu trả lời tốt nhất cho đến nay. Mã có thể bảo trì phân tách các mối quan tâm!
helsont

18
Tôi sẽ cẩn thận xem xét các tác động lâu dài của việc gọi trình gieo hạt từ các tập lệnh di chuyển. Các tập lệnh di chuyển được tạo phiên bản ngày / giờ, trong khi trình gieo hạt thường không. Trong quá trình phát triển, nhu cầu của trình tạo phiên bản thường thay đổi, dẫn đến khả năng các tập lệnh di chuyển có phiên bản chạy trình tạo phiên bản không có phiên bản - phá vỡ tính hiệu quả. Nói cách khác, việc chạy cùng một bộ tập lệnh di chuyển từ ngày này sang ngày khác có thể mang lại các kết quả khác nhau.
originalbryan

2
Đã lâu kể từ khi tôi đăng bài này và tôi muốn cung cấp trải nghiệm của chúng tôi bằng cách sử dụng kỹ thuật này. Nhìn chung, nó đã hoạt động tốt cho chúng tôi và nếu tôi phải làm lại điều đó thì tôi sẽ làm. Điều đó nói rằng có một điểm cần lưu ý. @originalbryan hoàn toàn đúng và hậu quả là chúng tôi đôi khi gặp phải tình huống di chuyển bị hỏng khi quay một DB mới bởi vì khi di chuyển chạy trình gieo hạt (và mô hình) cập nhật nhiều hơn cơ sở dữ liệu (vì chúng tôi có thể bắt đầu trước khi lược đồ được cập nhật đầy đủ). Khi điều đó xảy ra, chúng tôi cập nhật quá trình di chuyển cũ để giải quyết vấn đề.
darrylkuhn

@darrylkuhn Tôi nghe nói rằng nó không phải là thực hành tốt để cập nhật file chuyển cũ - thay vì cập nhật các tập tin cũ, bạn nên tạo tập tin chuyển đổi mới - đây là "công việc" cho việc di chuyển tập tin bằng cách thiết kế
Kamil Kiełczewski

2
Tất cả ngôn ngữ của Laravel đều ngụ ý trình tạo hạt giống là dữ liệu thử nghiệm, vì vậy tôi nghĩ điều đó nên được ghi nhớ khi thiết kế. Điều quan trọng là phải phân biệt giữa dữ liệu là một phần của ứng dụng với dữ liệu thử nghiệm và việc bao gồm dữ liệu bắt buộc trực tiếp trong quá trình di chuyển sẽ tạo ra sự khác biệt rất rõ ràng.
Brettins

13

Đây là lời giải thích rất hữu ích về lý do tại sao việc sử dụng Database Seeder của Laravel lại được ưu tiên hơn so với việc sử dụng Migrations: http://laravelbook.com/laravel-database-seeding/

Mặc dù, làm theo các hướng dẫn trên tài liệu chính thức là một ý tưởng tốt hơn nhiều vì việc triển khai được mô tả tại liên kết ở trên dường như không hoạt động và không hoàn chỉnh. http://laravel.com/docs/migrations#database-seeding


1
Tôi đồng ý với bạn Erin. Không trộn dữ liệu di chuyển với dữ liệu gốc vì rất có thể bạn muốn đưa một số dữ liệu vào môi trường phát triển nhưng không phải trong môi trường sản xuất của bạn.
Daniel Vigueras

18
Điểm tốt, nhưng có một số tình huống mà một số dữ liệu phải tồn tại trong môi trường sản xuất. Ví dụ: phải tồn tại người dùng quản trị mặc định đầu tiên để khách hàng có thể đăng nhập lần đầu tiên, một số vai trò ủy quyền đặt trước phải tồn tại, một số dữ liệu logic nghiệp vụ cũng có thể được yêu cầu ngay lập tức. Vì vậy, tôi nghĩ dữ liệu bắt buộc nên được thêm vào các lần di chuyển (để bạn có thể tăng / giảm các bản ghi dữ liệu thông qua các lần di chuyển riêng biệt), nhưng có thể để lại hạt giống để phát triển.
JustAMartin

Một lưu ý nhỏ; liên kết đến cơ sở dữ liệu seeding bây giờ là: laravel.com/docs/5.3/seeding
magikMaker

3

Điều này sẽ làm những gì bạn muốn.

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

1

Một cách dễ thực hiện khác là xác định một phương thức riêng tư để tạo ra Mô hình liên quan đến instance et dai dẳng.

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

Với giải pháp này, các trường dấu thời gian sẽ được tạo bởi Eloquent.

CHỈNH SỬA: tốt hơn là sử dụng hệ thống seeder để tạo cấu trúc cơ sở dữ liệu riêng biệt và tập hợp cơ sở dữ liệu.


Tôi thích cái này ... nó phục vụ chính xác những gì tôi cần làm, thêm một vài vai trò người dùng theo mặc định khi di chuyển. Cần chắc chắn rằng nhập mô hình hoặc tham khảo trực tiếp nó $model = new App\UserRoles();, nhưng khác hơn là ... hoàn hảo!
FAB

1

Tôi đã thử phương pháp chèn DB này, nhưng vì nó không sử dụng mô hình, nên nó đã bỏ qua một đặc điểm có thể kéo được mà tôi có trên mô hình. Vì vậy, với Mô hình cho bảng này tồn tại, ngay sau khi nó được di chuyển, tôi nghĩ rằng mô hình sẽ có sẵn để sử dụng để chèn dữ liệu. Và tôi nghĩ ra điều này:

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

Điều này hoạt động chính xác và cũng đã tính đến đặc điểm có thể kéo được trên Mô hình của tôi để tự động tạo một slug cho mục nhập này và sử dụng cả dấu thời gian. NB. Việc thêm ID không cần thiết, tuy nhiên, tôi muốn có các ID cụ thể cho các danh mục của mình trong ví dụ này. Đã thử nghiệm hoạt động trên Laravel 5.8


0

Nếu bạn đã điền các cột và đã thêm cột mới hoặc bạn muốn điền vào cột cũ bằng các giá trị giả mới, hãy làm như sau:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.