Популяція бази даних у файлі міграції 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 (), оскільки метод створення повинен закінчити створення таблиці, перш ніж ви зможете вставити речі. Спробуйте це замість цього:

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
і як вставити кілька даних?
Сахбаз

6
@ SuperMario'sYoshi я думаю , що - щось на зразок цьогоDB::table('users')->insert([ ['email' => 'taylor@example.com', 'votes' => 0], ['email' => 'dayle@example.com', 'votes' => 0] ]);
Денис

80

Я знаю, що це стара публікація, але оскільки вона з’являється в пошуку в Google, я подумав, що поділюсь деякими знаннями тут. @ erin-geyer зазначав, що змішування міграцій та сівалок може створювати головні болі, а @justamartin протидіє, що іноді потрібно, щоб дані були заповнені як частина вашого розгортання.

Я б пішов ще на крок і сказав, що іноді бажано мати змогу послідовно розгортати зміни даних, щоб можна було, наприклад, розгортатись до інсценізації, бачити, що все добре, а потім розгортатись до виробництва з впевненістю у тих же результатах (і не потрібно пам'ятати, щоб виконати якийсь крок вручну).

Тим не менш, все ще існує цінність у відокремленні насіння та міграції, оскільки це дві пов'язані, але чіткі проблеми. Наша команда пішла на компроміс, створивши міграцію, яка викликає сівалок. Це виглядає так:

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

Це, очевидно, умовно виконується вашою сівалкою, якщо їх є менше 10 SomeModels. Це корисно, якщо ви хочете включити сівалку як стандартну сівалку, яка виконується під час виклику artisan db:seed, а також під час міграції, щоб не "подвоїти". Ви також можете створити зворотну сівалку, щоб відкати спрацювали так, як очікувалося, наприклад

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

Другий параметр --forceнеобхідний для того, щоб сівалка працювала у виробничих умовах.


2
Це, безумовно, найкраща відповідь. Бездоганний код, який розділяє проблеми!
helsont

18
Я буду обережно розглянути довгострокові наслідки виклику сівалок із сценаріїв міграції. Сценарії міграції залежать від дати та часу, а сівалки, як правило, ні. Під час розробки потреби в сівалках часто змінюються, що призводить до можливості розроблених сценаріїв міграції, що працюють у неперевірених сівалках - порушуючи ідентифікацію. Іншими словами, використання одного і того ж набору сценаріїв міграції з дня на день може давати різні результати.
originalbryan

2
Минув час, коли я опублікував це, і хотів розповісти про наш досвід використання цієї методики. В цілому це спрацювало добре для нас, і якби мені довелося це зробити заново, я би зробив це. Це сказало, що є один gotcha, який слід знати. @originalbryan абсолютно правильний, і наслідок цього - ми періодично стикаємося з ситуаціями, коли міграції зриваються, коли запускається свіжий БД, оскільки міграція запускає сівалку (і модель) є більш актуальною, ніж база даних (оскільки ми можемо насіти до повного оновлення схеми). Коли це станеться, ми оновлюємо стару міграцію для вирішення проблеми.
darrylkuhn

@darrylkuhn Я чую, що оновлювати старі файли міграції не надто практично - замість оновлення старих файлів слід створити новий файл міграції - це "робочий процес" для міграційних файлів за задумом
Kamil Kiełczewski

2
Вся мова Laravel передбачає, що сівалка призначена для тестових даних, тому я думаю, що слід пам’ятати про дизайн. Важливо розрізняти дані, що входять до складу програми від даних тесту, і включення необхідних даних безпосередньо під час міграції робить це розрізнення дуже чітко.
Бреттінс

13

Ось дуже вдале пояснення того, чому використання Seeder баз даних Laravel є кращим, ніж використання міграції: http://laravelbook.com/laravel-database-seeding/

Хоча, дотримуючись вказівок на офіційній документації, це набагато краща ідея, оскільки реалізація, описана у вищенаведеному посиланні, здається, не працює і є неповною. http://laravel.com/docs/migrations#database-seeding


1
Я згоден з тобою, Ерін. Не змішуйте міграцію з даними про насіння, оскільки велика ймовірність, що ви хотіли б посіяти деякі дані у вашому середовищі розробки, але не у виробничому середовищі.
Даніель Вігерас

18
Добре, але є деякі ситуації, коли деякі дані повинні існувати у виробничому середовищі. Наприклад, найперший користувач адміністратора за замовчуванням повинен існувати, щоб клієнт міг увійти вперше, повинні існувати деякі попередньо встановлені ролі авторизації, деякі бізнес-логічні дані також можуть бути потрібні негайно. Таким чином, я вважаю, що обов'язкові дані повинні бути додані до міграцій (щоб ви могли збільшити / знизити також записи даних шляхом окремих міграцій), але насіння можна залишити для розвитку.
JustAMartin

Невелика записка; посилання на висівання бази даних зараз: 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();
    }
}

За допомогою цього рішення поля часових міток будуть генеровані красномовними.

EDIT: краще використовувати систему сівалок для дезінфекції генерації структури бази даних та популяції баз даних.


Мені подобається цей ... він сервери саме те, що мені потрібно було зробити, додати декілька ролей користувача за замовчуванням при міграції. Потрібно переконатися або імпортувати модель, або посилатися безпосередньо на неї $model = new App\UserRoles();, але крім цього ... ідеально!
FAB

1

Я спробував цей метод вставлення в БД, але оскільки він не використовує модель, він проігнорував слухняну ознаку, яку я мав на моделі. Отже, враховуючи, що Модель для цієї таблиці існує, як тільки її міграція, я зрозумів, що модель буде доступна для вставки даних. І я придумав це:

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. Додавання ідентифікатора не потрібно, проте в цьому прикладі я хотів отримати конкретні ідентифікатори для своїх категорій. Тестовано, працюючи над Laravel 5.8


0

Якщо ви вже заповнили стовпці та додали новий або хочете заповнити старий стовпець новими макетними значеннями, зробіть це:

public function up()
{
    DB::table('foydabars')->update(
        array(
            'status' => '0'
        )
    );
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.