У меня есть проект 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, ]);
Вместо функции 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);
$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()
чтобы разделить его, если это так.