Php 仅在必要时对数据库中的相关Laravel模型进行计数的特性
我想知道,对于拉雷维尔来说,是否已经存在以下类似的情况?这是我写的一个叫做CarefulCount的特征 它的作用:它返回相关模型的计数(使用任何定义的关系),但仅在绝对必要时点击数据库。首先,如果信息已经可用,它会尝试两个选项以避免命中数据库:Php 仅在必要时对数据库中的相关Laravel模型进行计数的特性,php,laravel,eloquent,eloquent-relationship,Php,Laravel,Eloquent,Eloquent Relationship,我想知道,对于拉雷维尔来说,是否已经存在以下类似的情况?这是我写的一个叫做CarefulCount的特征 它的作用:它返回相关模型的计数(使用任何定义的关系),但仅在绝对必要时点击数据库。首先,如果信息已经可用,它会尝试两个选项以避免命中数据库: 检索模型时是否使用withCount('relation')检索计数,即$model->relationship\u count是否存在?如果是这样,就把它还给我 关系紧张吗?如果是这样,使用$model->relation->count(),在不点击
withCount('relation')
检索计数,即$model->relationship\u count
是否存在?如果是这样,就把它还给我$model->relation->count()
,在不点击数据库的情况下计算雄辩集合中的模型$model->relation()->count()
从数据库中检索计数use carefolcount
中即可。然后,您可以为任何定义的关系调用$model->carefolcount('relation')
例如,在我的应用程序中,有一个郊区
表,它与用户
表和教堂
表都有许多关系(即,在一个郊区可以有许多用户和许多教堂)。只需将使用carefolcount
添加到郊区
模型,我就可以调用$郊区->carefolcount('users')
和$郊区->carefolcount('churches')
我的用例:我已经遇到过很多次了——我需要一些相关的模型,但它位于我的应用程序的较低级别部分,可以从多个地方调用。因此,我不知道模型是如何检索的,以及计数信息是否已经存在
在这些情况下,默认情况是调用$model->relation()->count()
。但这可能会导致失败
事实上,具体的触发因素来自将Marcel Pociot的优秀软件包添加到我的项目中。它发现了许多我没有发现的N+1查询问题,大多数都是在我已经急切地加载相关模型的情况下出现的。但在我的刀片模板中,我使用策略来启用或禁用记录的删除;我的郊区政策
类的delete($user,$suburban)
方法包括:
return $suburb->users()->count() == 0 && $suburb->churches()->count() == 0;
这就引入了N+1问题——显然,在我的策略类(或模型类本身)中,我不能假设用户和教会都渴望加载。但随着carefolcounttrait的加入,这就变成了:
return $suburb->carefulCount('users') == 0 && $suburb->carefulCount('churches') == 0;
瞧!对此进行修补并检查查询日志,就可以了。例如,使用用户计数:
- 如果使用
检索到郊区::withCount('users')
,则不会执行额外的查询$郊区
- 类似地,如果使用('users')检索它,则不会执行额外的查询
- 如果以上两项都未执行,则执行
查询以检索计数selectcount(*)
use Illuminate\Support\Str;
trait CarefulCount
{
/**
* Implements a careful and efficient count algorithm for the given
* relation, only hitting the DB if necessary.
*
* @param string $relation
*
* @return integer
*/
public function carefulCount(string $relation): int
{
/*
* If the count has already been loaded using withCount('relation'),
* use the 'relation_count' property.
*/
$prop = Str::snake($relation) . "_count";
if (isset($this->$prop)) {
return $this->$prop;
}
/*
* If the related models have already been eager-loaded using
* with('relation'), count the loaded collection.
*/
if ($this->relationLoaded($relation)) {
return $this->$relation->count();
}
/*
* Neither loaded, so hit the database.
*/
return $this->$relation()->count();
}
}