我有一个方法需要从三个相关模型中提取信息。我有一个有效的解决方案,但我恐怕仍然在运行N+ 1查询问题(也在寻找如何检查我是否急于加载正确的解决方案)。
这三种模式分别是挑战型、进入型、用户型。
挑战模型包含:

 /**
 * Retrieves the Entrants object associated to the Challenge
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function entrants()
{
    return $this->hasMany('App\Entrant');
}

参赛者模型包括:
     /**
     * Retrieves the Challenge object associated to the Entrant
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function challenge()
    {
        return $this->belongsTo('App\Challenge', 'challenge_id');
    }

    /**
     * Retrieves the User object associated to the Entrant
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user()
    {
        return $this->belongsTo('App\User', 'user_id');
    }

用户模型包括:
 /**
 * Retrieves the Entrants object associated to the User
 * @return \Illuminate\Database\Eloquent\Relations\HasMany
 */
public function entrants()
{
    return $this->hasMany('App\Entrant');
}

我尝试使用的紧急加载方法如下:
/**
 * Returns an array of currently running challenges
 * with associated entrants and associated users
 * @return array
 */
public function liveChallenges()
{
    $currentDate = Carbon::now();
    $challenges = Challenge::where('end_date', '>', $currentDate)
        ->with('entrants.user')
        ->where('start_date', '<', $currentDate)
        ->where('active', '1')
        ->get();

    $challengesObject = [];
    foreach ($challenges as $challenge) {
        $entrants = $challenge->entrants->load('user')->sortByDesc('current_total_amount')->all();
        $entrantsObject = [];
        foreach ($entrants as $entrant) {
            $user = $entrant->user;
            $entrantsObject[] = [
                'entrant' => $entrant,
                'user' => $user
            ];
        }

        $challengesObject[] = [
            'challenge' => $challenge,
            'entrants' => $entrantsObject
        ];
    }

    return $challengesObject;
}

我觉得我遵循了文档建议:https://laravel.com/docs/5.5/eloquent-relationships#eager-loading
但不确定如何检查以确保我没有进行n+1查询,而不是仅进行2查询。欢迎对代码提出任何提示或建议,以及检查紧急加载是否正常工作的方法。

最佳答案

当您执行->with('entrants.user')时,当您到达->get()时,它将同时加载进入者和用户。当您执行->load('user')时,它会运行另一个查询来获取用户。但您不需要这样做,因为您在运行->with('entrants.user')时已经拉过它。
如果您使用->loadMissing('user')而不是->load('user'),则应防止冗余调用。
但是,如果你使用Collection methods,你可以在刚开始的1个查询中逃跑,在那里你声明“cc>:

foreach ($challenges as $challenge) {
    // at this point, $challenge->entrants is a Collection because you already eager-loaded it
    $entrants = $challenge->entrants->sortByDesc('current_total_amount');
    // etc...

您不需要使用$challenges,因为->load('user')已经填充了参赛者和相关用户。因此,您可以利用集合方法$challenge->entrants对PHP中的列表进行排序。
此外,您不需要运行->sortByDesc(),因为这样可以将它转换成一个模型数组(您可以将其保持为模型集合,并且仍然保留它)。

09-04 07:13
查看更多