我的两个表(客户和产品)使用Laravel的blongToMany和数据透视表建立了ManyToMany关系。现在,我要检查某个客户是否具有某个产品。
我可以创建一个模型来检查数据透视表,但是由于Laravel不需要将此模型用于belongsToMany方法,所以我想知道是否有另一种方法可以在没有数据透视表模型的情况下检查是否存在某种关系。
Answers:
我认为这样做的官方方法是:
$client = Client::find(1);
$exists = $client->products->contains($product_id);
这样做会很浪费,因为它将执行SELECT
查询,将所有结果放入Collection
,然后最终对进行一次foreach
以上的操作,Collection
以找到具有您传入ID的模型。但是,它不需要对数据透视表进行建模。
如果您不喜欢这样做,可以在SQL / Query Builder中自己做,这也不需要对表进行建模(Client
如果您还没有将其用于其他目的,也不需要获取模型) :
$exists = DB::table('client_product')
->whereClientId($client_id)
->whereProductId($product_id)
->count() > 0;
$exists = $client->products()->contains($product_id);
)执行,则确实会说contains
上不存在BelongsToMany
。但是,如果你把它作为一个属性,BelongsToMany被悄悄转化为集合,它确实有contains()
。
这个问题已经很老了,但这可能会帮助其他人寻找解决方案:
$client = Client::find(1);
$exists = $client->products()->where('products.id', $productId)->exists();
没有@alexrussell解决方案中的“浪费”,查询也更加有效。
where('products.id', $productId)
。
client
也具有ID,则需要别名。这很普遍。
Alex的解决方案正在工作,但它将把Client
模型和所有相关Product
模型从DB加载到内存中,然后,它将检查该关系是否存在。
更好的口才是使用whereHas()
method。
1.您无需加载客户端模型,只需使用其ID。
2.您也不需要像Alex一样将与该客户端相关的所有产品加载到内存中。
3.对数据库的一个SQL查询。
$doesClientHaveProduct = Product::where('id', $productId)
->whereHas('clients', function($q) use($clientId) {
$q->where('id', $clientId);
})
->count();
更新:我没有考虑检查多重关系的有用性,如果是这种情况,那么@deczo可以更好地回答这个问题。理想的解决方案是只运行一个查询以检查所有关系。
/**
* Determine if a Client has a specific Product
* @param $clientId
* @param $productId
* @return bool
*/
public function clientHasProduct($clientId, $productId)
{
return ! is_null(
DB::table('client_product')
->where('client_id', $clientId)
->where('product_id', $productId)
->first()
);
}
您可以将其放在用户/客户端模型中,也可以将其放在ClientRepository中,并在需要时使用它。
if ($this->clientRepository->clientHasProduct($clientId, $productId)
{
return 'Awesome';
}
但是,如果您已经在Client Eloquent模型上定义了EmiratesToMany关系,则可以在Client模型内部执行此操作:
return ! is_null(
$this->products()
->where('product_id', $productId)
->first()
);
@nielsiano的方法可以使用,但是它们将查询数据库的每个用户/产品对,这在我看来是浪费。
如果您不想加载所有相关模型的数据,那么这就是我要为单个用户执行的操作:
// User model
protected $productIds = null;
public function getProductsIdsAttribute()
{
if (is_null($this->productsIds) $this->loadProductsIds();
return $this->productsIds;
}
public function loadProductsIds()
{
$this->productsIds = DB::table($this->products()->getTable())
->where($this->products()->getForeignKey(), $this->getKey())
->lists($this->products()->getOtherKey());
return $this;
}
public function hasProduct($id)
{
return in_array($id, $this->productsIds);
}
然后,您可以简单地执行以下操作:
$user = User::first();
$user->hasProduct($someId); // true / false
// or
Auth::user()->hasProduct($someId);
仅执行1个查询,然后使用数组。
最简单的方法是使用contains
@alexrussell建议的方法。
我认为这是优先考虑的问题,因此,除非您的应用程序很大且需要大量优化,否则您可以选择更易于使用的内容。
col_id
以及哪些合格/前缀table.col_id
。不幸的是,口才经常缺乏一致性。
大家好)我针对这个问题的解决方案:我创建了一个自Eloquent扩展的类,并从中扩展了我的所有模型。在这一节课中,我编写了这个简单的函数:
function have($relation_name, $id) {
return (bool) $this->$relation_name()->where('id','=',$id)->count();
}
要检查现有关系,您必须编写类似以下内容的内容:
if ($user->have('subscribes', 15)) {
// do some things
}
这种方式只生成一个SELECT count(...)查询,而不从表中接收实际数据。
使用特征:
trait hasPivotTrait
{
public function hasPivot($relation, $model)
{
return (bool) $this->{$relation}()->wherePivot($model->getForeignKey(), $model->{$model->getKeyName()})->count();
}
}
。
if ($user->hasPivot('tags', $tag)){
// do some things...
}
要检查2个模型之间是否存在关系,我们需要的是对数据透视表的单个查询,没有任何联接。
您可以使用内置newPivotStatementForId
方法来实现:
$exists = $client->products()->newPivotStatementForId($product->id)->exists();
这有时间,但也许我可以帮助某人
if($client->products()->find($product->id)){
exists!!
}
请注意,您必须拥有产品和客户模型,希望对您有所帮助,