在 for-each 循环之外保存模型

Posted

技术标签:

【中文标题】在 for-each 循环之外保存模型【英文标题】:Save model outside of for-each loop 【发布时间】:2021-09-30 02:53:00 【问题描述】:

假设 模型顺序

class Order extends Model 
    use HasFactory;

    protected $table = 'order';

    protected $primaryKey   = 'id';
    public $incrementing = false;
    protected $keyType = 'string';
    protected $guarded = [];

    public function extra()
        return $this->hasOne(Extra::class);
    

    public function products()
        return $this->hasMany(Product::class);
    

Model Extra

class Extra extends Model 

    use HasFactory;
    protected $table = 'extra';
    protected $guarded = [];

    public function order()
        $this->belongsTo(Order::class);
    

模型产品

class Product extends Model 
    use HasFactory;
    protected $table = 'product';
    protected $guarded = [];
    public function order()
        return $this->belongsTo(Order::class);
    

现在,我从 API 接收数据。有了这些数据,我想提供模型,然后将信息存储到数据库。

有atm的做法是:

foreach ($list as $item) 
    $order = new Order();
    $order->id = $item['id'];
    $order->title = $item['title'];
    $order->save();

    $extra = new Extra();
    $extra->foo= $item['path']['to']['foo'];
    $extra->bar= $item['path']['to']['bar'];
    $order->extra()->save($extra)
    
    $order->products()->createMany($item['path']['to']['products']);

问题是这段代码为每个循环保存了 3 次,1 次用于订购,1 次用于额外,1 次用于产品。 我想知道是否可以使用另一种方法来收集 for-each 内部和外部的数据,以制作类似

Order::insert($array_of_data);

【问题讨论】:

是的,只需将要插入的数组保存到数组中,而不是将属性分配给模型并保存 @lagbox 感谢您的回答。有没有可能给我看一些代码来理解?此外,关系(一对一,一对多)呢?幕后的东西会照顾他们吗? 不,没有什么可以处理这样的事情,insert 无论如何都绕过了 eloquent ...您目前所做的已经足够了,因为您需要保存的记录及其关系 ID 如果可能的话,添加几行代码!谢谢 【参考方案1】:

我想它看起来像这样,试试看,如果不起作用,请告诉我,我会删除答案

$orders = [];
$extras = [];
$products = [];

foreach ($list as $item) 
   
    $orders[] = [
        'id' => $item['id'],
        'title' => $item['title'],
    ];

    $extras[] = [
        'foo' => $item['path']['to']['foo'],
        'bar' => $item['path']['to']['bar'],
    ];

    $products[] = [
       'order_id' => $item['id'],
       'foo' => $item['path']['to']['products']['foo'] // or data it has
    ];


Order::insert($orders);
Extra::insert($extras);
Product::insert($products); // make sure each product has order id and data which is not visible here

我还建议考虑将 $list 转换为集合,然后对其进行迭代,如果数据很大,您可以使用 LazyCollection,它与集合相同,但更适合处理更大的数据集

这是一个使用惰性收集的示例

LazyCollection::make($list)
    ->each(function (array $item) 
        $order = Order::create(
            [
                'id' => $item['id'], 
                'title' => $item['title']
            ],
        );
                
        Extra::create(
            [
                'order_id' => $item['id'], 
                'foo' => $item['path']['to']['foo'],
                'bar' => $item['path']['to']['bar'],
            ],
        );
                
        $order->products()->createMany($item['path']['to']['products']);
    );

虽然它不一定一次创建多个,但它是内存的救星,并且会很快处理

【讨论】:

以上是关于在 for-each 循环之外保存模型的主要内容,如果未能解决你的问题,请参考以下文章

for-each 循环如何工作? [复制]

为啥 for-each 循环适用于数组? (爪哇)

2优先使用for-each循环

For-Each循环

如何在没有 ConcurrentModificationException 的情况下使用 for-each 循环进行迭代时修改集合? [复制]

有没有办法在 for-each 循环迭代开始之前避免空检查? [复制]