Laravel 4.1的Eager Loading工作,但查询仍然在视图中执行


Laravel 4.1 Eager Loading working, but queries still executed in view

我有一个简单的"项目"模型。一个项目可以有许多任务,每个任务属于一个员工。我有一个页面,显示+- 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应该可以胜任这项任务。

我要在狼人的回答中添加一点:

1)获取对象的正确方法是:
$projects->with(array('tasks' => function($query)
{
    $query->select('project_id', 'employee_id')->distinct();
}))->get();

get是OUTSIDE,而不是inside for Eager Loading

2)你的功能任务(在项目内)应该有一个一对多的关系,指向一个任务模型与狼人提到的外键

3)热切加载使您能够提前加载N+1,例如,如果您需要在项目中引用Employee,则可以查看哪些任务分配给哪个员工,而不是运行

SELECT * FROM employee WHERE id = ?
为了从关系 中获取数据而运行的每个$task->employee()->name上的

所以急切加载将SELECT * FROM employee首先-然后在任务内将急切加载与WHERE IN(?,?,?)(请纠正我,如果我错了)

4)这让我想到了我的第四点,那就是急于加载员工,这将减少查询。在内部任务中建立一对多的函数关系

据此,应该使用projects表中的id字段和tasks表中的project_id字段来建立关系。还要确保在末尾调用了get()方法。

你可以在急切加载中使用select,但要确保你已经选择了关系构建器键,例如,如果你的Project有许多Task,而你的tasks表包含project_id作为foreign key,那么你需要在select中选择该外键。因此,确保project_idtasks表中作为foreign key可用,以建立与projects表的关系。例如,检查如下:

$r = Role::with(['users' => function($q) {
    $q->select('role_id', 'username');
}])->get();

我有users表,其中包含role_id作为外键来构建rolesusers表之间的关系,并且在Role模型中声明了one-to-many关系,因此我可以使用select()来急于加载相关的User模型(只有role_id和'用户名'将在相关的User模型中加载),但没有select中的role_id,我无法加载相关的User模型。

你不能依赖select()来处理急切加载,因为Eloquent可能需要所有模型的属性来正确地急切加载。要么取消选择,要么尝试在选择语句中添加更多列。

除了上面的答案,我将添加我自己的查询,它可以完美地加载每个项目的所有任务,以及员工和员工的配置文件。

$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

这工作得很好,并大大减少了我的查询量。