php 防止 Laravel 向数据透视表添加多条记录

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17472128/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 12:56:49  来源:igfitidea点击:

Preventing Laravel adding multiple records to a pivot table

phplaravellaravel-4eloquent

提问by Al_

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?

如果没有,如何检查数据透视表以查找匹配记录是否已存在?

采纳答案by Alexandre Butynski

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.

您还应该看看下面来自 Barryvdh 的更直接的答案。

回答by Barryvdh

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

您还可以使用该$model->sync(array $ids, $detaching = true)方法并禁用分离(第二个参数)。

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

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

更新:从 Laravel 5.3 或 5.2.44 开始,您还可以调用 syncWithoutDetaching:

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

Which does exactly the same, but more readable :)

这完全相同,但更具可读性:)

回答by Octavian Ruda

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

@alexandre Butynsky 方法效果很好,但使用了两个 sql 查询。

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) {}

回答by adeguk Loggcity

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)

与所有这些答案一样好是因为我已经尝试了所有答案,但仍有一件事没有得到解答或没有得到解决:更新先前选中的值的问题(未选中复选框 [es])。我确实有与上述问题类似的问题,希望我想在我的产品功能表(数据透视表)中检查和取消选中产品的功能。我是一个新手,我意识到以上没有做到这一点。添加新功能时两者都很好,但当我想删除现有功能时则不然(即取消选中它)

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:

对不起,伙计们,我不确定我是否应该删除这个问题,因为我自己已经找到了答案,这听起来有点愚蠢,上面的答案就像使用 @Barryvdh sync() 一样简单;阅读了越来越多的关于:

$features = $request->get('features');
if (isset($features) && Count($features)>0){
    $product->features()->sync($features);
}

回答by Shreyansh Panchal

You can just use

你可以使用

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

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

As of Laravel 5.7:

从 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:

同步关联您还可以使用同步方法来构建多对多关联。同步方法接受要放置在中间表上的 ID 数组。任何不在给定数组中的 ID 都将从中间表中删除。因此,此操作完成后,中间表中将只存在给定数组中的 ID:

回答by Peter de Kok

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.

@AlexandreButynski 和 @Barryvdh 的答案比我的建议更具可读性,这个答案增加了一些效率。

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.

它只检索当前组合的条目(实际上只有 id),如果它不存在则附加它。同步方法(即使没有分离)检索所有当前附加的 id。对于小迭代的较小集合,这几乎没有区别,......你明白我的意思。

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