Laravel 4.1 Eager正在加载工作,但查询仍然在视图中执行

时间:2014-06-26 22:02:47

标签: php mysql laravel-4 eager-loading

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

4 个答案:

答案 0 :(得分:2)

根据这一点,您的关系应使用id表的projects字段和project_id表的tasks字段构建。另外,请确保最后调用get()方法。

您可以在急切加载中使用select,但请确保选择了关系构建器密钥,例如,如果Project有多个Tasktasks表包含{ {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_idroles表之间的关系,并在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

这很有效,并且大大减少了查询量。