Home > Software design >  Laravel issue with updating hasMany relationship records
Laravel issue with updating hasMany relationship records

Time:12-21

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.

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;

My User model has the following;

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?

CodePudding user response:

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

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!

CodePudding user response:

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.

# query

If the brand has some unique key, you could use upsert instead of 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

CodePudding user response:

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.

And in place of foreach, you can use the map method.

CodePudding user response:

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'],
    ]
    );
}
  • Related