我有4个与层级相关的实体:Company
,Department
和Employee
。 Company
和Department
与ManyToOne双向关系相关。 Department
和Employee
通过具有2个OneToMany双向关系的另一个实体相关,因为我需要关系的其他参数。所以基本上最终的架构是这样的:
Company <-> Department <-> DepartmentEmployee <-> Employee
我试图从当前用户的公司中选择一个部门,并获得该部门的所有员工。我使用自定义存储库使用查询构建器构建我的查询,如下所示:
// DepartmentRepository.php
public function getOneWithEmployees($slug, $company)
{
$qb = $this->createQueryBuilder('d')
->where('d.slug = :slug')
->andWhere('c.slug = :company')
->setParameters(array('slug' => $slug, 'company' => $company))
->leftJoin('d.company', 'c')
->addSelect('c')
->leftJoin('d.departmentEmployee', 'r')
->addSelect('r')
->leftJoin('r.employee', 'e')
->addSelect('e');
return $qb->getQuery()->getOneOrNullResult();
}
重点是减少查询次数,但是当我执行此查询时,我仍然会对数据库进行32次查询(我在该部门有15名员工)。
当我删除部分时
->leftJoin('r.employee', 'e')
->addSelect('e')
我只按预期执行一个查询。
如何在不触发多重查询的情况下在左连接上执行左连接?
答案 0 :(得分:9)
我的Employee
实体是2个OneToOne关系的反面:User
和Invitation
。当我使用left join
在查询中明确包含这些关系时,不会进行额外的查询,但是如果我将它们排除在外,那么Doctrine会自动进行查询以获取它们。查看Doctrine FAQ我发现了这个:
4.7.1。为什么每次获取具有一对一关系的实体时都会执行额外的SQL查询?
如果Doctrine检测到您正在获取反向一对一关联,则必须执行另一个查询才能加载此对象,因为它无法知道是否没有此类对象(设置为null)或是否应该设置代理和此代理具有的ID。
要解决此问题,目前必须执行查询才能找到此信息。
因此避免额外查询的唯一解决方案是构建我的查询:
$qb = $this->createQueryBuilder('d')
->where('d.slug = :slug')
->andWhere('c.slug = :company')
->setParameters(array('slug' => $slug, 'company' => $company))
->leftJoin('d.company', 'c')
->addSelect('c')
->leftJoin('d.departmentEmployee', 'r')
->addSelect('r')
->leftJoin('r.employee', 'e')
->addSelect('e')
->leftJoin('e.user', 'u')
->addSelect('u')
->leftJoin('e.invitation', 'i')
->addSelect('i');
return $qb->getQuery()->getOneOrNullResult();