Laravel 预加载问题。如何修复收到的 N+1 警告?

Laravel eager loading problem. How do I fix the N+1 warning that I'm getting?

我有一个函数,我在一个循环中使用的视图中使用它。所以它被多次使用。我认为因此我有 N+1 问题。在我的函数中,我急切地加载模型,但我仍然收到 N+1 警告。

我在 TaskController 上的函数

public function appDefaultPassword($newUserAccount, $newUserId)
{

    // Check if application default_password is set
    if($this->application->default_password) {
        return $this->application->decryptDefaultPass();
        // Check if application use_network_password is true
    } elseif($this->application->use_network_password) {
        // Get newUserAccount

        $newUser = $newUserAccount->with('applications')->where('id', $newUserId)->first();
        $netapp = $newUser->applications->where('app_type', 'LDAP')->first();
        $tasks = $this->with('actions')->where('model_id', $newUserAccount->id)->where('application_id', $netapp->id)->first();
        $taskAction = $tasks->actions->where('password', !NULL)->last();

        return decrypt($taskAction->password);
    }
}

在我的 NewUserAccountController 中,我也很想加载应用程序和 task.actions

public function show($newUserAccount)
{
    $newUserAccount = NewUserAccount::with('applications', 'task.application.admins', 'task.actions', 'approvalActions')->find($newUserAccount);
}

在我看来:

@foreach($newUserAccount->task as $task)
...

    {{ $task->appDefaultPassword($newUserAccount->id) }}

...
@endforeach

我正在使用 Laravel N+1 查询检测器来检测这个 N+1 问题。 我不确定如何修复我的功能以满足此要求。

使用@Watercayman 建议...
更新代码:

appDefaultPassword 方法

$netapp = $newUserAccount->applications->where('app_type', 'LDAP')->first();
$tasks = $newUserAccount->task->where('model_id', $newUserAccount->id)->where('application_id', $netapp->id)->first();
foreach($tasks->actions as $taskAction);
$taskAction = $tasks->actions->where('password', !NULL)->last();

return decrypt($taskAction->password);

查看:

{{ $task->appDefaultPassword($newUserAccount) }}

您的观点是 最初 得到一个 $newUserAccount 并且急切加载 applications。因此,该循环中的 $newUserAccount collection 将加载 applications

但是,在那个 blade 页面上循环时,您正在将 newUserAccountid 传递回控制器,您正在加载一个全新的 newUserAccount 模型 每次在该循环中

此外,这一行:

$newUser = $newUserAccount->with('applications')->where('id', $newUserId)->first();

部分是您的 n+1 问题的来源。您的 $newUserAccount object 已从路由模型绑定进入(我假设,尽管您没有类型提示 - 但除非 object 进入,否则它会中断),但是您渴望在 blade 的每个循环中将 applications 加载到新实例上。

因此它正在发送 id,生成 newUserAccount object,然后一遍又一遍地加载应用程序。

该行还有另一个问题:$newUserAccount 已经是来自方法参数的单个 object - 它已经是第一个 object 基于id,但你是 运行 上面那一行就好像是 collection。我认为这可能是无关紧要的,但我不确定,因为我真的不知道参数中的 object 来自哪里。

要修复重复的数据库调用,请在方法中执行所有准备逻辑,然后发送到您的blade文件,而不是让blade 文件在 newUserAccount->tasks 的每个循环中不断回调控制器。换句话说,在第一次去 blade 之前,有 newUserAccounts,并提前得到一个 $taskAction->passwords 的列表,你可以从 [=49] 的逻辑中选择=]循环。