Eager Loading on laravel query when nested 3 deep

被刻印的时光 ゝ 提交于 2020-03-25 12:32:29

问题


I have Jobs and Projects in my Laravel site and there is a relationship between them. I'm trying to reduce the number of queries made (and be mindful of N+1 problem). I do this with eager loading in my controller when outputting my JobItems.

How can I do this when I nest: JobItems > Project > JobItems.

There is one instance where this happens and I am getting duplicate queries. I'm not sure how to eager load. I'll outline the situation:

Each JobItem has a column for hours.

In my project I SUM all associated JobItem hours to determine the total hours in a project. (Eg. 3 JobItems with 4hours each, I then have a an accessor in my Project Model that says projectHours = 12).

  • job
    • project
      • project_hours (SUM of associated jobs)

I want to list all JobItems and each JobItem to have a child element of the related Project.

So I am calling:

  1. JobItem Model
  2. Project Model (to put as a child in JobItem)
  3. JobItem Model (to calculate total hours in Project Model)

At this step 3 I am getting N+1 issue and multiple duplicate queries. I'd like to reduce this with eager loading, but not sure how if I am (in step 1) already calling the JobItem model.

In my controller I have:

    public function getJobItems()
    {

        $userId = auth()->user()->id;

        return JobItem::whereHas('project', function ($query) use ($userId) {
            $query->where('user_id', '=', $userId);
        })->with(['project', 'user'])
            ->get();
    }

In my Project model I have:

class Project extends Model
{

    protected $appends = ['projectHours'];


    public function jobs()
    {
        return $this->hasMany('App\JobItem', 'project_id', 'id');
    }

    public function getProjectHoursAttribute()
    {
        return $this->jobs->sum('hours');
    }

}

As always, if I am approaching this incorrectly let me know. Much appreciated.

NB. This is related to this SO ticket about reducing queries with Eager Loading: How to use eager loading on Laravel model with SUM of a relationship - currently getting multiple queries (N+1)


回答1:


I'm going to answer this in two parts:


1) Preloading Relationships

So if you are try to list out a jobItem collection but want to display an attribute of each item's associated Project's Jobs, you can preload the required relationships like so:

JobItem::with(['project.jobs'])->get();

The . operator can be used to access nested relationships. (It follows the same rules as loading any relationship in that it's the name of the relationship on the respective model)


2) Accessing Relationships

I notice that you are constraining a query by a user id even though you have a User model available. Provided you have a jobItems relationship on you User model, you could do this instead:

public function getJobItems()
{
    $user = auth()->user()->loadMissing(['jobItems.project.jobs']);

    return $user->jobItems;
}


来源:https://stackoverflow.com/questions/60354755/eager-loading-on-laravel-query-when-nested-3-deep

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!