Массовая вставка в Laravel с использованием красноречивого ORM

69

Как мы можем выполнять массовые вставки баз данных в Laravel с использованием Eloquent ORM?

Я хочу сделать это в Laravel: https://stackoverflow.com/questions/10615762/php-bulk-insert-foreach но я получаю следующую ошибку.

SQLSTATE [HY093]: Недопустимый номер параметра: смешанные имена и позиционные параметры.

  • 1
    У вас есть отношения has_many на ваших моделях?
  • 1
    @ jonathandey нет, у меня нет никаких отношений на данный момент
Показать ещё 4 комментария
Теги:
database
eloquent

8 ответов

160
Лучший ответ

Вы можете просто использовать Eloquent::insert().

Например:

$data = array(
    array('name'=>'Coder 1', 'rep'=>'4096'),
    array('name'=>'Coder 2', 'rep'=>'2048'),
    //...
);

Coder::insert($data);
  • 145
    Примечание: это не будет обновлять / создавать временные метки.
  • 2
    Это все еще относится к Laravel 4?
Показать ещё 16 комментариев
40

Мы можем легко обновить ответ GTF, чтобы обновить временные метки

$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=>date('Y-m-d H:i:s'),
        'modified_at'=> date('Y-m-d H:i:s')
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=>date('Y-m-d H:i:s'),
         'modified_at'=> date('Y-m-d H:i:s')
       ),
    //...
);

Coder::insert($data);

Обновление: чтобы упростить дату, мы можем использовать углерод, как предложил @Pedro Moreira

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'modified_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'modified_at'=> $now
       ),
    //...
);

Coder::insert($data);

UPDATE2: для laravel 5 используйте updated_at вместо modified_at

$now = Carbon::now('utc')->toDateTimeString();
$data = array(
    array(
        'name'=>'Coder 1', 'rep'=>'4096',
        'created_at'=> $now,
        'updated_at'=> $now
       ),
    array(
         'name'=>'Coder 2', 'rep'=>'2048',
         'created_at'=> $now,
         'updated_at'=> $now
       ),
    //...
);

Coder::insert($data);
  • 39
    Или используйте Carbon в начале скрипта, чтобы определить переменную $now : $now = Carbon::now('utc')->toDateTimeString(); , Затем просто используйте 'created_at' => $now, 'updated_at' => $now для каждой вставки.
  • 1
    Как мы можем получить все идентификаторы вновь вставленных строк?
Показать ещё 6 комментариев
12

Кому кто читает это, проверьте createMany() method.

/**
 * Create a Collection of new instances of the related model.
 *
 * @param  array  $records
 * @return \Illuminate\Database\Eloquent\Collection
 */
public function createMany(array $records)
{
    $instances = $this->related->newCollection();

    foreach ($records as $record) {
        $instances->push($this->create($record));
    }

    return $instances;
}
  • 2
    Пожалуйста, не публикуйте повторяющиеся ответы на несколько вопросов. Приспособьте свой ответ на вопрос.
  • 19
    @ miken32 И вот идет полиция переполнения стека;) Я просто хотел оставить записку для отчаявшихся гуглеров вроде меня, вот и все. Ответ совершенно очевиден.
Показать ещё 3 комментария
6

Вот как вы делаете это более красноречиво,

    $allintests = [];
    foreach($intersts as $item){ //$intersts array contains input data
        $intestcat = new User_Category();
        $intestcat->memberid = $item->memberid;
        $intestcat->catid= $item->catid;
        $allintests[] = $intestcat->attributesToArray();
    }
    User_Category::insert($allintests);
0

Я много раз искал для него, наконец использовал пользовательский timestamps, как показано ниже:

$now = Carbon::now()->toDateTimeString();
Model::insert([
    ['name'=>'Foo', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Bar', 'created_at'=>$now, 'updated_at'=>$now],
    ['name'=>'Baz', 'created_at'=>$now, 'updated_at'=>$now],
    ..................................
]);
0

Возможно, более Laravel-способ решить эту проблему - использовать коллекцию и петлю, которую она вставляет с помощью модели, использующей отметки времени.

<?php

use App\Continent;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        collect([
            ['name' => 'América'],
            ['name' => 'África'],
            ['name' => 'Europa'],
            ['name' => 'Asia'],
            ['name' => 'Oceanía'],
        ])->each(function ($item, $key) {
            Continent::forceCreate($item);
        });
    }
}

EDIT:

Извините за мое недоразумение. Для массового вставки это может помочь, и, возможно, с этим вы можете сделать хорошие сеялки и немного их оптимизировать.

<?php

use App\Continent;
use Carbon\Carbon;
use Illuminate\Database\Seeder;

class InitialSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $timestamp = Carbon::now();
        $password = bcrypt('secret');

        $continents = [
            [
                'name' => 'América'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'África'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Europa'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Asia'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
            [
                'name' => 'Oceanía'
                'password' => $password,
                'created_at' => $timestamp,
                'updated_at' => $timestamp,
            ],
        ];

        Continent::insert($continents);
    }
}
  • 0
    Это делает один запрос на элемент. Это не массовая вставка.
  • 1
    @EmileBergeron Я согласен с тобой. Я отредактировал свой пост, так что, возможно, это могло бы помочь получить хорошую массовую вставку. Если вы оставите задачи, которые занимают много времени вне цикла (carbon, bcrypt), это может сэкономить вам много времени.
0

Или при использовании Laravel Factories (создание 10 пользователей):

$users = factory(App\User::class, 10)->make()->toArray();

App\User::insert($users);
-1
$start_date = date('Y-m-d h:m:s');        
        $end_date = date('Y-m-d h:m:s', strtotime($start_date . "+".$userSubscription['duration']." months") );
        $user_subscription_array = array(
          array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', ),
array(
            'user_id' => $request->input('user_id'),
            'user_subscription_plan_id' => $request->input('subscription_plan_id'),
            'name' => $userSubscription['name'],
            'description' => $userSubscription['description'],
            'duration' => $userSubscription['duration'],
            'start_datetime' => $start_date,
            'end_datetime' => $end_date,
            'amount' => $userSubscription['amount'],
            'invoice_id' => '',
            'transection_datetime' => '',
            'created_by' => '1',
            'status_id' => '1', )
        );
        dd(UserSubscription::insert($user_subscription_array));

UserSubscription - мое имя модели. Это вернет "true", если вставить успешно else "false".

Ещё вопросы

Сообщество Overcoder
Наверх
Меню