Laravel - 具有关系的多表插入

时间:2018-04-29 16:35:57

标签: php laravel eloquent

创建订单时我应该填充3个表格,我想知道最好的方法。

表格

Orders
- id (pk)
- company_id
- address_id (join to items table)
- date
- source
- ...

Addresses
- id (pk)
- company_id
- name
- email
- address
- ...

Items
- id (pk)
- order_id (join to orders table)
- product_id
- qty
- ...

关系

  • 地址表所属于订单表
  • 订单包含多件商品
  • 我们有一个多租户(单一数据库)结构,因此company_id用于在公司之间分隔数据。订单和地址都属于公司。

创作

我的理解是,首先需要创建地址才能获取ID。然后创建订单,然后是项目。

我还想确保如果任何插入失败,则不会保存任何数据(如在SQL事务中)。

我想知道是否有人可以指出我正确的方向来做到这一点的最佳方式?到目前为止,我有以下

$address = OrderAddress::create([
    'company_id' => Auth::user()->company_id,
    'name' => 'test test',
    'email' => 'test@test.com',
    'address' => '78 test street',
]);
$order = $address->order()->create([
    //'address_id' => populated by model
    'company_id' => Auth::user()->company_id,
    'date' => '2018-03-23',
    'source' => 'mystore'
]);
foreach($items as $item){
    OrderItem::create([
        'order_id' => $order->order_id,
        'product_id' => $item->product_id,
        'qty' => $item->qty
    ]);
}

我的主要问题是:

  1. 这不能用作交易,即失败不会产生回滚。
  2. 我不确定我是否充分利用模特关系。

2 个答案:

答案 0 :(得分:1)

您可以做出基本上两项改进。每个问题都有一个。

  1. 要将事务中的所有内容包装起来,可以将create语句放在DB::transaction(...)块中。如需参考,请查看the manual。还有另一种使用那里描述的交易的方式。

  2. 您在创建create时使用的相同关系Order方法也可应用于OrderItems$order->items()->create([...])

  3. 最终的代码段可能如下所示:

    DB::transaction(function () {
        $address = OrderAddress::create([
            'company_id' => Auth::user()->company_id,
            'name' => 'test test',
            'email' => 'test@test.com',
            'address' => '78 test street',
        ]);
        $order = $address->order()->create([
            'company_id' => Auth::user()->company_id, // actually, this information is already available through the `address`
            'date' => '2018-03-23',
            'source' => 'mystore'
        ]);
        foreach($items as $item){
            $order->items()->create([
                'order_id' => $order->order_id,
                'product_id' => $item->product_id,
                'qty' => $item->qty
            ]);
        }
    });
    

    如果关系名称被调用orderItems()而不是items(),请务必更改关系名称。

答案 1 :(得分:1)

DB :: transaction(...)

DB ::的BeginTransaction();

您可以通过rollBack方法回滚事务:

DB ::回滚();

最后,您可以通过提交方法提交事务:

DB ::提交();