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

我有一个多对多的关系设置和工作,添加一个项目的购物车,我使用:

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

它向 pivot 表中添加了一个条目(这是应该的) ,但是如果用户再次单击链接来添加他们已经添加的条目,就会在 pivot 表中创建一个重复条目。

是否有一种内建的方法,只在数据透视表中不存在记录时才将其添加到数据透视表中?

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

63862 次浏览

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

或者/并且您可以在您的数据库中添加统一性条件,它会在尝试保存 double 时抛出异常。

你也应该看看来自 Barryvdh 的更直接的答案。

@ alexandre Butynsky 方法工作得很好,但需要使用两个 sql 查询。

一个用于检查购物车是否包含该项目,另一个用于保存。

若要只使用一个查询,请使用:

try {
$cart->items()->save($newItem);
}
catch(\Exception $e) {}

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

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

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

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

它的作用完全相同,但更具可读性:)

所有这些答案都很好,因为我已经全部试过了,但有一个问题仍然没有得到解决: 更新之前选中的值的问题(未选中选中的复选框[ es ])。我确实有一些类似于上面的问题,我希望在我的产品特性表(轴心表)中检查和取消检查产品特性。我是一个新手,我没有意识到以上任何一个做到了这一点。当添加新特性时,这两个选项都很好,但是当我想删除现有特性时就不行了(比如,取消选中它)

我会很感激你的启发。

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

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

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

已经有一些很棒的答案发布了,不过我想把这个也放在这里。

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

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

无论如何,它肯定是不可读的,但它的诀窍。

if (is_null($book->authors()->find($author->getKey(), [$author->getQualifiedKeyName()])))
$book->authors()->attach($author);
$branch->permissions()->syncWithoutDetaching([1,2,3]);

我只是有这个问题,并能够解决它。

对于将来的读者: 您可以使用

syncWithoutDetaching()

这将确保您不会得到任何副本!

还有更多的附加()选项

这在 幼虫检疫证明文件中可能很有用

注意,这不是针对 Laravel 4的