Зареждане на база данни - вмъкнете множество записи в една заявка

Имам проект на Laravel, където бих искал да вмъкна над 900 града в база данни като зареждане на база данни.

Например мога да го направя по следния начин:

$state_id = State::whereName('state name')->pluck('id');

$city = new City();
$city->name = 'my city name';
$city->state_id = $state_id;
$city->save();

и в моя градски модел дефинирах запазване като:

public function save(array $options = array()) {
    $this->url = $this->createUrl($this->name);
    parent::save($options);
}

така че създава и URL адрес за града.

Мога да поставя 900 пъти такъв блок от кодове, но има един проблем - той ще се изпълнява в отделни заявки, така че ще отнеме над 30 секунди, за да вмъкнете тези данни в базата данни.

Мога да го направя например по следния начин:

DB::table('cities')->insert(
    [
        [
            'name' => 'City name',
            'url' => Slug::create('City name'),
            'created_at' => $now,
            'updated_at' => $now,
            'state_id' => $state_id
        ],
        [
            'name' => 'City name 2',
            'url' => Slug::create('City name 2'),
            'created_at' => $now,
            'updated_at' => $now,
            'state_id' => $state_id
        ],
    ]);

и по този начин мога да вмъкна много записи в една SQL заявка, но според мен това не е много хубаво решение - трябва ръчно да настроя всички полета на базата данни, но отнема само 3-4 секунди, за да вмъкна всички данни в базата данни.

Въпросът е - възможно ли е да се създават модели и с помощта на някакъв магически метод да се връща готов PHP масив, за да се използва при вмъквания на множество файлове (прочетох, че Eloquent не може да се използва за вмъкване на множество записи в една заявка)?

Мисля, че много по-добре би било да се кодира нещо подобно:

$state_id = State::whereName('state name')->pluck('id');

$city = new City();
$city->name = 'my city name';
$city->state_id = $state_id;
$city1 = $city->saveFake(); // magic method that returns complete array

$city = new City();
$city->name = 'my city name';
$city->state_id = $state_id;
$city2 = $city->saveFake(); // magic method that returns complete array

DB::table('cities')->insert(
    [
        $city1,
        $city2,
    ]);

person Marcin Nabiałek    schedule 22.08.2014    source източник


Отговори (2)


Вместо вашата функция saveFake(), можете да направите:

$city->attributesToArray()

Това ще върне всички атрибути, които трябва да бъдат съхранени в таблицата.

Можете да ги добавите към масив и да го поставите във функция за вмъкване.

Това ще доведе до нещо подобно:

$state_id = State::whereName('state name')->pluck('id');
$cities = array();

$city = new City();
$city->name = 'my city name';
$city->state_id = $state_id;
$cities[] = $city->attributesToArray();

$city = new City();
$city->name = 'my city name';
$city->state_id = $state_id;
$cities[] = $city->attributesToArray();

DB::table('cities')->insert($cities);
person PaulusDixit    schedule 22.08.2014
comment
Страхувам се, че не работи. Ще върне само name и state_id в масив, но не и други полета (created_at, modified_at или url, което се изчислява въз основа на name във функцията save) - person Marcin Nabiałek; 22.08.2014
comment
Можете да ги добавите ръчно към вашия модел. Просто добавете attributesToArray() и добавете полетата, които искате да добавите ръчно. И извикайте родителската функция. - person PaulusDixit; 22.08.2014
comment
Въпросът е, че не искам да ги добавям ръчно. Ако исках, щях да използвам метода, който показах в моя въпрос, където дори не трябва да създавам модел - person Marcin Nabiałek; 22.08.2014
comment
Ако искате всички променливи, можете да използвате toArray(). Приложихте ли вече мутатор за вашия URL адрес? като getUrlAttribute($value) - person PaulusDixit; 22.08.2014

$cities = [];
$cities[] = new City(...);
$cities[] = new City(...);
$table = with(new City)->getTable();
$data = array_map(function($city) {
    return $city->getAttributes();
}, $cities);
DB::table($table)->insert($data);

getAttributes връща „суровите“ основни атрибути, които са вмъкнати в базата данни.

Имайте предвид, че това ще заобиколи Eloquent събития като запазване/създаване.

Също така имайте предвид, че ако $data стане твърде голям, може да срещнете проблеми с паметта. Използвайте нещо като array_chunk(), за да го разделите, ако случаят е такъв.

person Andreas    schedule 26.08.2014