【问题标题】:Database seeding - insert multiple records in one query数据库播种 - 在一个查询中插入多条记录
【发布时间】:2014-08-22 11:08:49
【问题描述】:

我有一个 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,
    ]);

【问题讨论】:

    标签: php laravel laravel-4 seeding


    【解决方案1】:

    您可以使用 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);
    

    【讨论】:

    • 恐怕不行。它只会在数组中返回namestate_id,而不是其他字段(created_atmodified_aturl,这是根据namesave 函数中计算的)
    • 您可以手动将它们添加到您的模型中。只需添加 attributesToArray() 并添加您想要手动添加的字段。并调用父函数。
    • 重点是我不想手动添加。如果我愿意,我会使用我在我的问题中展示的方法,我什至不必创建模型
    • 如果你想要所有的变量,你可以使用toArray()。你是否已经为你的 URL 实现了一个 mutator?喜欢getUrlAttribute($value)
    【解决方案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 返回插入数据库的“原始”基础属性。

    请记住,这将绕过 Eloquent 事件,例如保存/创建。

    另外请记住,如果$data 变大,您可能会遇到内存问题。如果是这种情况,请使用 array_chunk() 之类的东西将其拆分。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-07
      • 2012-12-16
      • 1970-01-01
      • 2017-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-30
      相关资源
      最近更新 更多