简体   繁体   English

Laravel Eloquent更新相关记录

[英]Laravel Eloquent update related records

I have two mysql tables我有两个 mysql 表

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

very simple two tables.很简单的两张表。 I am having issue while want to update any record, like when I edit some sales record I can我在想要更新任何记录时遇到问题,比如当我编辑一些销售记录时,我可以

  1. add new item添加新项目
  2. modify previously added item修改之前添加的项目
  3. or delete previously added item或删除之前添加的项目

Now I want to update sales_items tables also.现在我也想更新 sales_items 表。

What I am doing now is我现在正在做的是

  1. first deleting all records of sales in sales_items table首先删除sales_items表中的所有销售记录
  2. Add new records添加新记录
$task = Auth::user()->sales_items()->where(['sales_id'=>1]);
$task->delete();

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

code is working but is this correct approach or there is batter way to do that?代码正在工作,但这是正确的方法还是有更好的方法来做到这一点? I am using Laravel 8 Eloquent and all tables have models我正在使用 Laravel 8 Eloquent 并且所有表都有模型

Thanks谢谢

Normally this type of update process is a bit lengthy but efficient and optimal as compared to delete and insert hack, there are many benefits of this approach通常,与删除和插入 hack 相比,这种类型的更新过程有点冗长但高效且最佳,这种方法有很多好处

  • Primary key of a records remains same as compared to other approach which creates a new record and assign a new primary key与创建新记录并分配新主键的其他方法相比,记录的主键保持不变
  • You can track update_at timestamp which will change on every update while in case of delete/insert the created_at and updated_at will have same values forever您可以跟踪update_at时间戳,该时间戳将在每次更新时更改,而在删除/插入的情况下, created_atupdated_at将永远具有相同的值
  • No unnecessary auto increments added on database side, like sale 1 has 3 records with id 1,2,3 and on update without changing any data the records will be deleted and inserted again and their ids will be 4,5,6 and next auto increment will be set to 7在数据库端没有添加不必要的自动增量,例如销售 1 有 3 条记录,id 为 1,2,3,更新时不更改任何数据,记录将被删除并再次插入,它们的 id 将是 4,5,6 和下一个自动增量将设置为 7

Lets say in database you already have 2 rows for sale 1假设在数据库中您已经有 2 行待售 1

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

Let say you have following collection to perform update for sale 1假设您有以下收藏来执行更新出售 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
    ]
]);

Now if we compare database results and the requested update collection we can see the there is现在,如果我们比较数据库结果和请求的更新集合,我们可以看到有

  • one insert for first item in collection because id is null一个插入集合中的第一项,因为 id 是 null
  • one update for second item in collection because id 1 exists in database对集合中的第二项进行一次更新,因为 id 1 存在于数据库中
  • one delete because in requested collection there is no item with id 2 so that needs to be deleted一次删除,因为在请求的集合中没有 id 为 2 的项目,因此需要删除

To perform above updates first we need to collect all items where id is null so we will add these records in database要首先执行上述更新,我们需要收集 id 为 null 的所有项目,因此我们将这些记录添加到数据库中

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

For update we need to collect items where id is present and these records will be updated in database as对于更新,我们需要收集 id 存在的项目,这些记录将在数据库中更新为

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

Or we can use upserts for first and second step as或者我们可以在第一步和第二步中使用upsert

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

For delete we can get all ids from collection and perform delete operation on rows that do not match these ids as对于删除,我们可以从集合中获取所有 id,并对不匹配这些 id 的行执行删除操作

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

You have 2 options:您有 2 个选项:

1. Use Eloquent events 1.使用Eloquent事件

# 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;
    });
}

This should run whenever a Sale or Item fire the deleting event.这应该在销售或项目触发删除事件时运行。 I'm not sure if mass-deletion works correctly.我不确定批量删除是否正常工作。

2. UseDatabase foreign key constraints 2.使用数据库外键约束

# sales_items table migration

$table->foreignId('item_id')
      ->constrained('items')
      ->onUpdate('cascade')
      ->onDelete('cascade');

$table->foreignId('sales_id')
      ->constrained('sales')
      ->onUpdate('cascade')
      ->onDelete('cascade');

This should delete automatically the sales_items record if they are associated with an item or sales that just got deleted.如果 sales_items 记录与刚刚被删除的项目或销售相关联,这应该会自动删除它们。 However, this will NOT work with softDeletes.但是,这不适用于 softDeletes。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM