Laravel 4.1:如何对雄辩的渴望关系进行分页?

2021-12-26 00:00:00 php laravel eloquent pagination

有关于旧的 L3 预加载分页的问题,而不是使用 eloquent.但我想使用 eloquent 来获得与分页的急切加载关系.

There was question about old L3 eager loaded paginations, not using eloquent. But i want to use eloquent to get eager loaded relationship with pagination.

主模型:与帖子有一对多关系的主题,这样一个主题就有很多帖子.我使用此功能获取所有数据:

Main model: Topic that has one to many relationship with Posts, So that one Topic has many Posts. I get all data with this function:

public function findById($id)
{
    return $this->topic->with('posts', 'posts.user', 'posts.user.profile')
                       ->find($id);
}

然后我循环显示所有结果,但它们没有分页:

And later I make loop to display all results, but they are not paginated:

@foreach($topic->posts as $post)
... unpaginated content ...
@endforeach

因此,我可以采取一种解决方法并分别选择所有具有主题 $id 的帖子并使用 ->paginate() 而不是 ->get() 并且会得到分页 $pots,

So, i could make a workaround and select separately all posts that has $id of topic and use ->paginate() instead of ->get() and would got paginated $pots,

  1. 但是是否有可能使用分页的急切加载关系帖子?怎么做?

推荐答案

澄清一些事情:对急切加载的关系进行分页是一种误解.急切加载的要点是在尽可能少的查询中检索所有关系.如果要检索 10 个主题,所有主题都有 35 个帖子,则只需要两个查询.甜!

To clarify something: paginating eager-loaded relationships is somewhat of a misconception. The point of eager loading is to retrieve all relationships in as few queries as you can. If you want to retrieve 10 topics, all of which have 35 posts, you will only need two queries. Sweet!

也就是说,对急切加载的关系进行分页是行不通的.考虑发生急切加载时的两种情况:

That said, paginating an eager-loaded relationship is not going to work. Consider two scenarios when eager loading happens:

  1. 您想要检索和列出主题,并且可能列出每个主题的前五个帖子.伟大的!急切加载是完美的.现在,您不希望在这样的页面上对急切加载的帖子进行分页,所以没关系.

  1. You want to retrieve and list topics, and maybe list the first five posts for each topic. Great! Eager loading is perfect. Now, you wouldn't want to paginate the eager-loaded posts on a page like this, so it doesn't matter.

您加载了一个主题,并且想要为该主题的帖子分页.伟大的!比较容易做到.但是,如果您已经预先加载了属于该主题的所有 帖子,那么您可能只是检索了许多您不需要的额外资源.因此,急切加载实际上伤害你.

You load a single topic, and you want to paginate the posts for that topic. Great! Relatively easy to do. However, if you've already eager-loaded all posts belonging to this topic, you've just potentially retrieved a lot of extra resources that you don't need. Therefore eager loading is actually hurting you.

也就是说,有两种可能的解决方案:

That said, there are two potential solutions:

选项 1:创建一个自定义访问器来对 Eloquent 关系进行分页.

Option 1: Create a custom accessor that paginates the Eloquent relationship.

/**
 * Paginated posts accessor. Access via $topic->posts_paginated
 * 
 * @return IlluminatePaginationPaginator
 */
public function getPostsPaginatedAttribute()
{
    return $this->posts()->paginate(10);
}

优点:非常容易分页;不干扰正常的帖子关系.
缺点:急切加载帖子不会影响此访问器;运行它将在预先加载的查询之上创建两个额外的查询.

Pros: Paginates very easily; does not interfere with normal posts relationship.
Cons: Eager loading posts will not affect this accessor; running it will create two additional queries on top of the eager loaded query.

选项 2:对急切加载关系返回的帖子集合进行分页.

Option 2: Paginate the posts Collection returned by the eager-loaded relationship.

/**
 * Paginated posts accessor. Access via $topic->posts_paginated
 * 
 * @return IlluminatePaginationPaginator
 */
public function getPostsPaginatedAttribute()
{
    $posts = $this->posts;

    // Note that you will need to slice the correct array elements yourself.
    // The paginator class will not do that for you.

    return Paginator::make($posts, $posts->count(), 10);
}

优点:使用急切加载关系;不创建额外的查询.
缺点:无论当前页面如何,都必须检索所有元素(慢);必须手动构建当前页面元素.

Pros: Uses the eager-loaded relationship; creates no additional queries.
Cons: Must retrieve ALL elements regardless of current page (slow); have to build the current-page elements manually.

相关文章