【问题标题】:Laravel Eloquent update related recordsLaravel Eloquent 更新相关记录
【发布时间】:2021-02-14 13:55:23
【问题描述】:

我有两个mysql表

1. sales (id,buyer_id)
2. sales_items (id,sales_id,item_id,price,quantity)

很简单的两张表。 我在想更新任何记录时遇到问题, 比如当我编辑一些销售记录时,我可以

  1. 添加新项目
  2. 修改之前添加的项目
  3. 或删除之前添加的项目

现在我还想更新 sales_items 表。

我现在正在做的是

  1. 先删除sales_items表中的所有销售记录
  2. 添加新记录
$task = Auth::user()->sales_items()->where(['sales_id'=>1]);
$task->delete();

//$SalesProducts array have all rows
SaleItem::insert($SalesProducts);

代码正在运行,但这是正确的方法还是有更好的方法来做到这一点? 我正在使用 Laravel 8 Eloquent,所有表都有模型

谢谢

【问题讨论】:

  • 没有简单的方法可以找出您编辑了哪些项目。最好的方法是将您编辑的sales_items 发送到您的更新控制器。
  • 在 laravel 8 中的 upsert 怎么样?
  • 使用 upsert 有什么问题吗?

标签: php mysql laravel eloquent


【解决方案1】:

与删除和插入黑客相比,这种类型的更新过程通常有点冗长但高效且最佳,这种方法有很多好处

  • 与创建新记录并分配新主键的其他方法相比,记录的主键保持不变
  • 您可以跟踪 update_at 时间戳,该时间戳将在每次更新时更改,而在删除/插入的情况下,created_at 和 updated_at 将永远具有相同的值
  • 在数据库端没有添加不必要的自动增量,例如销售 1 有 3 条 ID 为 1、2、3 的记录,在不更改任何数据的情况下更新记录将被删除并再次插入,它们的 ID 将为 4、5、6并且下一个自动增量将设置为 7

假设在数据库中您已经有 2 行待售 1

______________________________________________
| id | sales_id | item_id | price | quantity |
----------------------------------------------
|  1 |   1      |    1    |  20   |   5      |
----------------------------------------------
|  2 |   1      |    2    |  10   |   5      |
----------------------------------------------

假设您有以下收藏来执行更新出售 1

$collection = collect([
    [
        "id"=> null,
        "sales_id"=>1,
        "item_id"=> 1,
        "price"=>10,
        "quantity"=> 0
    ],
    [
        "id"=> 1,
        "sales_id"=>1,
        "item_id"=> 1,
        "price"=>10,
        "quantity"=> 0
    ]
]);

现在,如果我们比较数据库结果和请求的更新集合,我们可以看到有

  • 因为 id 为空,所以对集合中的第一项进行插入
  • 因为数据库中存在 id 1,所以对集合中的第二个项目进行了一次更新
  • 一次删除,因为在请求的集合中没有 id 为 2 的项目,因此需要删除

首先要执行上述更新,我们需要收集所有 id 为 null 的项目,以便我们将这些记录添加到数据库中

$addItems = $collection->whereNull('id'); 
if($addItems->count() > 0){
    SaleItem::insert($addItems);
}

为了更新,我们需要收集存在 id 的项目,这些记录将在数据库中更新为

$updateItems = $collection->whereNotNull('id');
foreach($updateItems as $key => $updateItem) {
    SaleItem::where('id', $updateItem->id)->update($updateItem);
}

或者我们可以在第一步和第二步中使用upserts

SaleItem::upsert($updateItems, ['id']);

对于删除,我们可以从集合中获取所有id,并对不匹配这些id的行执行删除操作

$deleteItems = $updateItems->pluck('id');
SaleItem::whereNotIn('id', $deleteItems)->delete();

【讨论】:

    【解决方案2】:

    您有 2 个选择:

    1。使用Eloquent events

    # Sale model
    protected static function booted()
    {
        static::deleting(function ($sale) {
            SaleItems::where('sales_id', $sale->id)->delete();
            return true;
        });
    }
    
    # Item model
    protected static function booted()
    {
        static::deleting(function ($item) {
            SaleItems::where('item_id', $item->id)->delete();
            return true;
        });
    }
    

    这应该在销售或物品触发删除事件时运行。我不确定批量删除是否正常工作。

    2。使用Database foreign key constraints

    # sales_items table migration
    
    $table->foreignId('item_id')
          ->constrained('items')
          ->onUpdate('cascade')
          ->onDelete('cascade');
    
    $table->foreignId('sales_id')
          ->constrained('sales')
          ->onUpdate('cascade')
          ->onDelete('cascade');
    

    如果 sales_items 记录与刚刚被删除的商品或销售相关联,这应该会自动删除它们。但是,这不适用于 softDeletes。

    【讨论】:

    • 对不起,我没有要求删除,我要求更新
    猜你喜欢
    • 1970-01-01
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    • 2021-07-21
    相关资源
    最近更新 更多