我正在做正确的加载吗? (雄辩)

问题描述 投票:3回答:2

我有一个方法需要从三个相关模型中提取信息。我有一个有效的解决方案,但我担心我仍然遇到N + 1查询问题(也在寻找解决方案,我可以检查我是否渴望正确加载)。

这三个模型是Challenge,Entrant,User。

挑战模型包含:

 /**
 * 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

但不确定如何检查以确保我没有做出反对2的N + 1查询。欢迎任何有关代码的提示或建议,以及检查热切加载是否正常工作的方法。

php laravel orm eloquent
2个回答
2
投票

当你做->with('entrants.user')时,一旦你到达->get()它就会加载进入者和用户。当你执行->load('user')时,它会运行另一个查询来获取用户。但你不需要这样做,因为你在运行->with('entrants.user')时已经拉过它。

如果你使用->loadMissing('user')而不是->load('user'),它应该阻止冗余调用。

但是,如果你利用Collection methods,你可以在你声明$challenges的开头只运行1个查询:

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...

您不需要使用->load('user'),因为$challenge->entrants已经填充了参赛者和相关用户。所以你可以利用Collection方法->sortByDesc()对php中的列表进行排序。

此外,您不需要运行->all(),因为这会将其转换为模型数组(您可以将其保留为模型集合并仍然可以预测它)。


3
投票

使用Laravel Debugbar检查Laravel应用程序为每个请求创建的查询。

您的Eloquent查询应该只生成3个原始SQL查询,您需要确保此行不会生成N个其他查询:

$entrants = $challenge->entrants->load('user')->sortByDesc('current_total_amount')->all()
© www.soinside.com 2019 - 2024. All rights reserved.