如何在没有 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 类别,这似乎有点过分了。急切加载文章和做-&gt;count() 会影响性能吗?或者这是最好的方法吗?

【问题讨论】:

你为什么不这样做:count($articleCategory-&gt;articles);?我认为这是最简单、最快速的。 感谢您的回复。我可以使用该方法,但理想情况下我不想加载所有相关文章。我已经更新了我的问题。 加载多个 Eloquent 模型是多余的。如果您有 100 行,那么您不必担心,但是对于数千行,我肯定不会那样做。 【参考方案1】:

试试这个

public function index()

    return View::make('categories.index', [
        'category' => Category::with('articles')->where('type', 'articles')->orderBy('name')->get(),
    ]);

现在在 View 中获取类别数据就行了

$category-&gt;type 或者如果您有名称字段,您可以通过$category-&gt;name 获取名称

要获取你可以做的类别的文章

foreach($category->articles as $article)
// do something with the articles
@endforeach

要获取某个类别的文章数量,请执行$category-&gt;articles-&gt;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 关系?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不重新加载整个页面的情况下刷新 div?

计算与加载 OpenGL 的法线

如何在不重新加载整个页面的情况下重新加载 div?

如何在没有内存错误的情况下加载巨大的时间序列 Windows 数据集?

如何在不刷新整个页面的情况下重新加载组件?

如何在给定旋转点,旋转角度和旋转轴(n-2子空间)的情况下计算n维旋转矩阵