我有一个在循环中使用的视图中使用的函数。因此它被多次使用。我认为正因为如此,我遇到了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) }}
答案 0 :(得分:2)
您的视图最初是 获得了一个$newUserAccount
并急切加载了applications
。因此,该循环中的$newUserAccount
集合将加载applications
。
但是,在该刀片页面上循环时,您将id
的{{1}}传递回控制器,在那里您要加载全新的newUserAccount
模型在该循环中的时间。
此外,此行:
newUserAccount
部分是您的$newUser = $newUserAccount->with('applications')->where('id', $newUserId)->first();
问题的来源。您的n+1
对象是从路由模型绑定中传入的(我想,尽管您没有类型提示,但是除非该对象进入,否则它将断开),但是您渴望加载{{1 }}在刀片的每个循环中的新实例上。
因此它正在发送$newUserAccount
,创建applications
对象,然后一遍又一遍地加载应用程序。
该行还有另一个问题:id
已经是来自方法参数的单个对象-它已经是基于newUserAccount
的第一个对象,但是您是运行上面的行,就好像它是一个集合。我认为这可能是多余的,但是我不确定,因为我真的不知道该对象在哪里。
要解决重复数据库调用的问题,请在发送到刀片文件之前,使用$newUserAccount
方法 进行所有准备逻辑,而不是让刀片文件继续回调给控制器在id
的每个循环中。换句话说,在第一次进行刀片操作之前,请先获取appDefaultPassword()
,并提前获取newUserAccount->tasks
的列表,您可以从刀片循环的逻辑中进行选择。