如何在没有 N+1 问题和加载整个模型的情况下计算 eloquent 关系?
Posted
技术标签:
【中文标题】如何在没有 N+1 问题和加载整个模型的情况下计算 eloquent 关系?【英文标题】:How to count eloquent relationship without the N+1 issue and loading the entire model? 【发布时间】:2014-11-18 04:03:05 【问题描述】:我正在显示一个类别列表,以及每个类别中的文章数。我得到了预期的结果,但我遇到了 N+1 问题。
我的CategoriesController
索引函数:
public function index()
return View::make('categories.index', [
'articleCategories' => Category::where('type', 'articles')->orderBy('name')->get(),
]);
Category
模型与文章有很多关系:
public function articles()
return $this->hasMany('Article');
我的categories.index
视图:
@foreach($articleCategories as $articleCategory)
<p>
html::link(URL::route('articles.category', array('category' => Str::slug($articleCategory->name))), $articleCategory->name)
$articleCategory->articles->count()
</p>
@endforeach
编辑:如果我渴望加载所有相关文章,它会起作用,但由于我只需要文章计数 pr 类别,这似乎有点过分了。急切加载文章和做->count()
会影响性能吗?或者这是最好的方法吗?
【问题讨论】:
你为什么不这样做:count($articleCategory->articles);
?我认为这是最简单、最快速的。
感谢您的回复。我可以使用该方法,但理想情况下我不想加载所有相关文章。我已经更新了我的问题。
加载多个 Eloquent 模型是多余的。如果您有 100 行,那么您不必担心,但是对于数千行,我肯定不会那样做。
【参考方案1】:
试试这个
public function index()
return View::make('categories.index', [
'category' => Category::with('articles')->where('type', 'articles')->orderBy('name')->get(),
]);
现在在 View 中获取类别数据就行了
$category->type
或者如果您有名称字段,您可以通过$category->name
获取名称
要获取你可以做的类别的文章
foreach($category->articles as $article)
// do something with the articles
@endforeach
要获取某个类别的文章数量,请执行$category->articles->count();
确保您还阅读过一次Eager loading 的文档,这确实很有帮助。
【讨论】:
谢谢,这个方法我很熟悉。但由于我只需要计数,因此加载所有相关文章似乎有点过头了。这会影响性能吗? 我明白你的意思,我认为不会有太大的性能问题,但我能想到的另一种方法是左加入类别模型上的文章,然后计算文章数量在 countArticles 方法中。我相信传统方法。【参考方案2】:// helper relation
public function articlesCount()
return $this->hasOne('Article')->selectRaw('category_id, count(*) as aggregate')->groupBy('category_id');
// and accessor for fetching it easier
public function getArticlesCountAttribute()
if ( ! array_key_exists('articlesCount', $this->relations)) $this->load('articlesCount');
return $this->getRelation('articlesCount')->aggregate;
那么你可以这样做:
// eager load in single query
$categories = Category::with('articlesCount')->get();
// thanks to accessor this will return value and load relation only if needed
$categories->first()->articlesCount;
【讨论】:
再次感谢 Jarek,还没有时间尝试这个。我会接受的。以上是关于如何在没有 N+1 问题和加载整个模型的情况下计算 eloquent 关系?的主要内容,如果未能解决你的问题,请参考以下文章