Preventing Laravel adding multiple records to a pi

2019-03-07 19:00发布

I have a many to many relationship set up and working, to add an item to the cart I use:

$cart->items()->attach($item);

Which adds an item to the pivot table (as it should), but if the user clicks on the link again to add an item they have already added it creates a duplicate entry in the pivot table.

Is there a built in way to add a record to a pivot table only if one does not already exist?

If not, how can I check the pivot table to find if a matching record already exists?

6条回答
戒情不戒烟
2楼-- · 2019-03-07 19:30

You can also use the $model->sync(array $ids, $detaching = true) method and disable detaching (the second param).

$cart->items()->sync([$item->id], false);

Update: Since Laravel 5.3 or 5.2.44, you can also call syncWithoutDetaching:

$cart->items()->syncWithoutDetaching([$item->id]);

Which does exactly the same, but more readable :)

查看更多
等我变得足够好
3楼-- · 2019-03-07 19:32

You can just use

$cart->items()->sync($items)

As of Laravel 5.7:

Syncing Associations You may also use the sync method to construct many-to-many associations. The sync method accepts an array of IDs to place on the intermediate table.Any IDs that are not in the given array will be removed from the intermediate table. So, after this operation is complete, only the IDs in the given array will exist in the intermediate table:

查看更多
神经病院院长
4楼-- · 2019-03-07 19:42

There are some great answers posted already. I wanted to throw this one out here as well though.

The answers from @AlexandreButynski and @Barryvdh are more readable than my suggestion, what this answer adds is some efficiency.

It retrieves only the entries for the current combination (actually only the id) and it than attaches it if it does not exist. The sync method (even without detaching) retrieves all currently attached ids. For smaller sets with little iterations this will hardly be a difference, ... you get my point.

Anyway, it is definitely not as readable, but it does the trick.

if (is_null($book->authors()->find($author->getKey(), [$author->getQualifiedKeyName()])))
    $book->authors()->attach($author);
查看更多
家丑人穷心不美
5楼-- · 2019-03-07 19:48

@alexandre Butynsky method works very well but use two sql queries.

One to check if cart contains the item and one to save.

To use only one query use this:

try {
    $cart->items()->save($newItem);
}
catch(\Exception $e) {}
查看更多
疯言疯语
6楼-- · 2019-03-07 19:53

As good as all this answers are because I had tried them all, one thing is still left unanswer or not taken care of: the issue of updating a previously checked value (unchecked the checked box[es]). I do have something similar to the above question expect i want to check and uncheck features of products in my product-feature table (the pivot table). I am a newbie and I have realised none of the above did that. The are both good when adding new features but not when i want to remove existing features (i.e. uncheck it)

I will appreciate any enlightenment in to this.

$features = $request->get('features');

if (isset($features) && Count($features)>0){
    foreach ($features as $feature_id){
        $feature = Feature::whereId($feature_id)->first();
        $product->updateFeatures($feature);
    }
}

//product.php (extract)
public function updateFeatures($feature) {
        return $this->features()->sync($feature, false);
}

or

public function updateFeatures($feature) {
   if (! $this->features->contains($features))
        return $this->features()->attach($feature);
}
//where my attach() is:
public function addFeatures($feature) {
        return $this->features()->attach($feature);
}

Sorry guys, not sure is I should delete the question because having figure out the answer myself, it sounds a bit stupid, well the answer to the above is as simple as working @Barryvdh sync() as follows; having read more and more about:

$features = $request->get('features');
if (isset($features) && Count($features)>0){
    $product->features()->sync($features);
}
查看更多
冷血范
7楼-- · 2019-03-07 19:57

You can check the presence of an existing record by writing a very simple condition like this one :

if (! $cart->items->contains($newItem->id)) {
    $cart->items()->save($newItem);
}

Or/and you can add unicity condition in your database, it would throw an exception during an attempt of saving a doublet.

You should also take a look at the more straightforward answer from Barryvdh just below.

查看更多
登录 后发表回答