代码之家  ›  专栏  ›  技术社区  ›  Steve

Laravel-急装

  •  1
  • Steve  · 技术社区  · 6 年前

    我试图理解使用laravel来避免生成大量不必要的查询的急切加载。我想获取最后添加的15个帖子,并从我的费率表的关系中获取它们的费率(在我获取帖子之前,稍后在foreach中,我调用了$item->avgrate(),它创建了15个附加查询:s)。

    我的帖子模型:

    public function rates()
    {
        return $this->hasMany(Rate::class);
    }
    
    public function scopeLastAdded($query, $limit = 15)
    {
        return $query->latest()->limit($limit)->with('rates')->get();
    }
    

    这是可行的,对于每个帖子,我也得到了所有的费率,但主要目标是建立一些函数来计算每个帖子的平均费率,而不是检索所有费率。我创建了一个新方法:

    public function avgRate()
    {
        return number_format($this->rates()->avg('rate'), 1, '.', '');
    }
    

    当我使用 with('avgRate') 我的模型失败了:

    对字符串调用成员函数addIngeConstraints()。

    我怎样才能在过去的15篇文章中以一种干净的方式得到avgrate,只执行2个查询,而不执行16个查询?

    预期输出:

    // Post view
    @foreach ($posts as $post)
       <div>{{ $post->title }}</div>
       <div>{{ $post->avgRate }}</div> //I want to get data without performing 15 queries
    @endforeach
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Mozammil    6 年前

    我将使用子查询来实现这一点。此外,为了使事情更清晰一点,您可以创建一个范围来获取评级:

    public function scopeWithRating($query)
    {
        $rating = Rate::selectRaw('AVG(rate)')
            ->whereColumn('post_id', 'posts.id')
            ->getQuery();
    
        $query->select('posts.*')
            ->selectSub($rating, 'rating');
    }
    

    …要使用它,你需要:

    Post::withRating()->get(); 
    

    现在,你 Post 对象还将包含一列 rating ,这基本上是用一个查询完成的。

    这里有一个 example 为了说明这一点。