【问题标题】:Doctrine2 left join on multiple levels making multiple requestsDoctrine2 在多个级别上左连接发出多个请求
【发布时间】:2014-03-15 19:05:39
【问题描述】:

我有 4 个层次相关的实体:CompanyDepartmentEmployeeCompanyDepartment 与多对一双向关系相关。 DepartmentEmployee 通过另一个具有 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')

我只得到一个按预期执行的查询。

如何在不触发多个查询的情况下对左连接进行左连接?

【问题讨论】:

  • 你能用$qb-&gt;getQuery()-&gt;getResult();代替$qb-&gt;getQuery()-&gt;getOneOrNullResult();吗?您的请求可能只选择一名员工,并要求其他员工提出更多请求。
  • 不,结果是一样的。但我想我找到了为什么要进行所有这些额外的查询。我会在下面解释。
  • 好吧,抱歉,我以为 getOneOrNullResult() 只会获取一个 Employee,但它必须只获取一个 Department(及其员工),这是正确的。
  • 没错。两种方法都返回一个Department,除了getResult() 被封装在一个数组中。

标签: symfony join doctrine-orm left-join


【解决方案1】:

我的 Employee 实体是 2 个 OneToOne 关系的反面:UserInvitation。当我使用left join 在查询中明确包含这些关系时,不会进行额外的查询,但是如果我将它们排除在外,那么 Doctrine 会自动进行查询以获取它们。查看 Doctrine FAQ 我发现了这个:

4.7.1。为什么每次获取具有一对一关系的实体时都会执行额外的 SQL 查询?

如果 Doctrine 检测到您正在获取反向的一对一关联,它必须执行附加查询来加载此对象,因为它不知道是否没有这样的对象(设置为 null)或者是否应该设置一个代理以及该代理的 ID。

为了解决这个问题,目前必须执行一个查询来找出这个信息。

Link

因此,避免额外查询的唯一解决方案是像这样构建我的查询:

$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();

【讨论】:

  • 跟题有什么区别?您添加了userinvitation
  • 是的。 Doctrine 自动进行查询以获取 OneToOne 关系的拥有方。所以为了避免额外的查询,关系必须包含在带有左连接的查询中。
猜你喜欢
  • 2016-05-20
  • 2010-10-03
  • 2013-06-16
  • 2019-09-03
  • 2015-04-10
  • 2012-03-13
  • 1970-01-01
  • 2021-07-02
  • 2021-12-29
相关资源
最近更新 更多