我有一个简单的“项目”模型。项目可以有许多任务,每个任务都属于一个员工。 我有一个页面显示+ - 100个项目,以及所有相关(独特)的员工。这导致执行了500多个查询,因此页面加载时间暴涨到不可接受的水平。所以我试着加急试试:
$projects->with(array('tasks' => function($query)
{
$query->select('project_id', 'employee_id')->distinct()->get();
}));
据我所知,通过调试,这给了我想要的结果。对于每个项目,正确检索任务,没有重复的员工。
然而。当我尝试在视图中加载任务时,Laravel仍在执行400多个查询以检索每个项目的任务。
@foreach ($projects as $project)
@foreach($project->tasks as $task)
@if($task->employee_id != 0 )
<img src="{{UserHelper::getGravatarUrl($task->employee->id)}}" alt="{{{ $task->employee->name }}}"
@endif
@endforeach
@endforeach
我尝试使用tasks()
和tasks()->get()
代替,但无济于事。如何访问预先加载的属性?
我不喜欢使用脏的原始查询,因为Eloquent应该完成任务。
答案 0 :(得分:2)
根据这一点,您的关系应使用id
表的projects
字段和project_id
表的tasks
字段构建。另外,请确保最后调用get()
方法。
您可以在急切加载中使用select,但请确保选择了关系构建器密钥,例如,如果Project
有多个Task
且tasks
表包含{ {1}} project_id
然后您需要在foreign key
中选择该外键。因此,请确保select
表中的project_id
可用tasks
来构建与foreign key
表的关系。例如,请检查:
projects
我有$r = Role::with(['users' => function($q) {
$q->select('role_id', 'username');
}])->get();
表,其中包含users
作为外键来构建role_id
和roles
表之间的关系,并在users
中声明了one-to-many
关系{1}}模型,因此我可以使用Role
来加载相关的select()
模型(只有User
和'用户名'将加载到相关的role_id
模型中) User
中的role_id
我无法加载相关的select
模型。
答案 1 :(得分:2)
我要在WereWolf的回答中添加一些内容:
1)获取对象的正确方法是:
$projects->with(array('tasks' => function($query)
{
$query->select('project_id', 'employee_id')->distinct();
}))->get();
get是OUTSIDE,而不是Eager Loading。
2)你的函数任务(在项目中)应该有一对多的关系,指向具有外键的任务模型,如WereWolf所述
3)Eager Loading使您可以提前加载N + 1,例如,如果您需要引用项目内的Employee,那么可以查看哪些任务转到哪个员工而不是运行
SELECT * FROM employee WHERE id = ?
在您运行的每个$task->employee()->name
上,以便从关系中获取数据
首先急切加载SELECT * FROM employee
- 然后在任务中急切加载WHERE IN(?,?,?)(如果我错了,请纠正我)
4)让我到第四点就是急切加载员工,这将减少查询。建立一对多内部任务的函数关系。
答案 2 :(得分:0)
您不能依赖select()
工作进行急切加载,因为Eloquent可能需要所有模型的属性才能正确加载。要么摆脱选择,要么尝试在select语句中添加更多列。
答案 3 :(得分:0)
除了上述答案之外,我还将添加自己的查询,该查询完全适用于每个项目的所有任务,以及员工和员工的配置文件。
$projects->with(array('tasks' => function($query)
{
$query->groupBy('project_id', 'employee_id')->with(array('employee.profiles'));
}));
我在我看来是这样访问这些:
@foreach($projects as $project)
@foreach($project->tasks as $task)
@if($task->employee_id != 0 )
<img src="{{UserHelper::getGravatarUrl($task->employee)}}" alt="{{{ $task->employee->name }}}">
@endif
@endforeach
@endforeach
这很有效,并且大大减少了查询量。