Php 仅在必要时对数据库中的相关Laravel模型进行计数的特性

Php 仅在必要时对数据库中的相关Laravel模型进行计数的特性,php,laravel,eloquent,eloquent-relationship,Php,Laravel,Eloquent,Eloquent Relationship,我想知道,对于拉雷维尔来说,是否已经存在以下类似的情况?这是我写的一个叫做CarefulCount的特征 它的作用:它返回相关模型的计数(使用任何定义的关系),但仅在绝对必要时点击数据库。首先,如果信息已经可用,它会尝试两个选项以避免命中数据库: 检索模型时是否使用withCount('relation')检索计数,即$model->relationship\u count是否存在?如果是这样,就把它还给我 关系紧张吗?如果是这样,使用$model->relation->count(),在不点击

我想知道,对于拉雷维尔来说,是否已经存在以下类似的情况?这是我写的一个叫做CarefulCount的特征

它的作用:它返回相关模型的计数(使用任何定义的关系),但仅在绝对必要时点击数据库。首先,如果信息已经可用,它会尝试两个选项以避免命中数据库:

  • 检索模型时是否使用
    withCount('relation')
    检索计数,即
    $model->relationship\u count
    是否存在?如果是这样,就把它还给我
  • 关系紧张吗?如果是这样,使用
    $model->relation->count()
    ,在不点击数据库的情况下计算雄辩集合中的模型
  • 然后才调用
    $model->relation()->count()
    从数据库中检索计数
  • 要为任何模型类启用它,只需将trait包含在
    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();
        }
    }