简体   繁体   English

更新 hasMany 关系记录的 Laravel 问题

[英]Laravel issue with updating hasMany relationship records

I have a User model which has a hasMany relationship to a Brands model and I am having issues updating the Brands for a user properly.我有一个 User 模型,它与 Brands 模型有很多关系,我在为用户正确更新 Brands 时遇到问题。

I have a form which allows a user to enter / delete / update their own Brands in text fields, the current method i am using to update the users Brands after they have entered them all or edited them is to delete all existing Brands associated with the User then loop over the values, create the Brand model and then 'saveMany'... But i seem to be getting a constraint violation when adding... I am wondering if there is a better way to do this;我有一个表单,允许用户在文本字段中输入/删除/更新他们自己的品牌,当前我用来更新用户品牌的方法是在他们输入所有品牌或编辑它们后删除所有与然后用户遍历这些值,创建品牌模型,然后“saveMany”……但是我在添加时似乎违反了约束……我想知道是否有更好的方法来做到这一点;

My User model has the following;我的User模型具有以下内容;

public function brands()
{
    return $this->hasMany('Brands::class');
}

Then in my controller I have the following code to update the Brands;然后在我的控制器中,我有以下代码来更新品牌;

$user->brands()->delete();

foreach ($request['brands'] as $brand) {
    $brandArray[] = new Brand([
        'name' => $brand['name'],
        'rating' => $brand['rating'],
    ]);
}

!empty($brandArray) && $user->brands()->saveMany($brandArray);

Is there a better way of doing this?有更好的方法吗?

Since you only want to delete all the previous brands of the user, and create brand new brands without editing anything, you can simply follow the concept below:由于您只想删除用户以前的所有品牌,而无需编辑任何内容即可创建全新的品牌,因此您可以简单地遵循以下概念:

In your controller:在你的控制器中:

// Step 1) load all the user brands
   $user->load('brands');

// Step 2) delete all the brands with this user
   $user->brands()->delete();

// Step 3) create all the new brands.
   $user->brands()->createMany($request['brands']);
   
/* Concept of how createMany works:
The brand array should look similar to this, you can do dd($request['brands']) to verify
   $user->brands()->createMany([
       ['name' => 'A new name.', 'rating' => '1'],
       ['name' => 'Another new name.', 'rating' => '2'],
   ]);
*/

You can find more examples in laravel documentation on createMany method: https://laravel.com/docs/9.x/eloquent-relationships#the-create-method您可以在有关 createMany 方法的 laravel 文档中找到更多示例: https ://laravel.com/docs/9.x/eloquent-relationships#the-create-method

You can also go a step further and validate the array from the request:您还可以更进一步并根据请求验证数组:

$data = request()->validate([
    'brands.*' => 'required',
]);
        
$user->brands()->createMany($data['brands']);

Hope this helps, good luck!希望这有帮助,祝你好运!

Let's separate things into three parts:让我们把事情分成三个部分:

# constraint key violation: # 违反约束键:

If you've added foreign key constraint on another table, and you need to delete the brands, you should also delete all those related data constrained by your foreign key.如果你在另一个表上添加了外键约束,你需要删除品牌,你也应该删除所有被你的外键约束的相关数据。

# design # 设计

If deleting brand related data is not possible, then maybe we can think about if there is a better design.如果不能删除品牌相关数据,那么或许我们可以考虑一下有没有更好的设计。 Maybe we could add a hook on the frontend that call a DELETE API whenever certain data is removed by the user.也许我们可以在前端添加一个挂钩,每当用户删除某些数据时调用 DELETE API。

# query # 询问

If the brand has some unique key, you could use upsert instead of saveMany.如果品牌有一些唯一的键,您可以使用upsert而不是 saveMany。 That will be more efficient.这样会更有效率。

# conclusion # 结论

I would suggest deleting brands by hooks on the frontend whenever a brand is removed by users, and use upsert to deal with create and update stuff我建议每当用户删除品牌时通过前端的挂钩删除品牌,并使用upsert来处理create and update内容

It looks fine to me.我觉得不错。 But from my point of view,但从我的角度来看,

Instead of deleting all fields, then creating them.而不是删除所有字段,然后创建它们。 You can use updateOrCreate eloquent method inside your foreach .您可以在foreach中使用updateOrCreate雄辩的方法。

And in place of foreach , you can use the map method.您可以使用map方法代替foreach

When you save everything you have for the user, do this under:当您为用户保存所有内容时,请在以下位置执行此操作:

foreach ($request['brands'] as $brand) {
    Brand::updateOrCreate(
    [
      'name' => $brand['name'],
        'rating' => $brand['rating'],
    ],
    [
      'name' => $brand['name'],
        'rating' => $brand['rating'],
    ]
    );
}

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

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