Database seeding - insert multiple records in one query

☆樱花仙子☆ 提交于 2020-03-04 05:56:51

问题


I have a Laravel project where I would like to insert above 900 cities into database as database seeding.

For example I could do it this way:

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

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

and in my City model I have defined save as:

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

so it creates also url for the city.

I can put 900 times such block of codes but there is one problem - it will run in separate queries, so it will take above 30 seconds to insert those data to database.

I can do it for example this way:

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

and this way I can insert many records in one SQL query but in my opinion it's not very nice solution - I need to manually set all database fields but it takes only 3-4 seconds to insert all the data into database.

The question is - is it possible to create models and using some magic method return ready PHP array to use it in multpile inserts ( I read that Eloquent cannot be used to insert multiple records in one query) ?

I think much better would be code something like this:

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

回答1:


Instead of your saveFake() function you could do:

$city->attributesToArray()

This will return all the attributes that have to be stored in the table.

You could add these to an array and put it in an insert function.

This would result in something like this:

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



回答2:


$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 returns the "raw" underlying attributes that are inserted into the database.

Keep in mind that this will bypass Eloquent events like saving/creating.

Also keep in mind that if $data becomes to big, you might run into memory issues. Use something like array_chunk() to split it up if that's the case.



来源:https://stackoverflow.com/questions/25445607/database-seeding-insert-multiple-records-in-one-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!