Doctrine生成大量查询以显示具有子实体的实体

时间:2016-03-27 23:21:20

标签: php symfony doctrine-orm doctrine

我有以下数据库结构(简化)。所有关系都是多对一

表格父级:

ID | SOME_DATA
-------------------------------
1  | Lorum
2  | Ipsum
..etc

表格儿童:

ID | PARENT_ID | SOME_DATA
-------------------------------
1  | 2         | Dolor
2  | 5         | Sis
..etc

使用普通的学说方法将它们全部显示在一个页面上:

<?php
//get parents
$parents = $this->getDoctrine()->getRepository('FamilyBundle:Parent')->findAll();

//loop through parents
foreach($parents AS $parent){

  //display parent
  echo '<h1>'.$parent->getName().'</h1>';

  //show children
  foreach($parent->getChildren() AS $child)
    echo '<h2>'.$child->getName().'</h2>';
}

使用首次亮相工具时,我惊讶地发现,为了检索子实体,每个父实体都使用一个新的数据库查询。导致脚本效率非常低。

上面的例子是简化的。如果我不依赖于实体类中的一些专门方法,我可以使用原始查询所以我的问题是,有没有办法做一个更聪明的查询,但仍然能够使用doctrine实体管理器管理数据,这样我仍然可以访问实体类方法。最好,我会喜欢指定父实体的哪些子项被预加载,因为我不需要使用它们。

任何人都可以指出我正确的方向吗?

1 个答案:

答案 0 :(得分:4)

如果查询中没有join子句,Doctrine默认使用“延迟加载”,因此您必须为父实体创建自定义存储库类以减少逻辑查询数。

只需将存储库注释添加到Parent实体类:

// FamilyBundle\Entity\Parent.php
namespace FamilyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="FamilyBundle\Repository\ParentRepository")
 */
class Parent {
  protected $children; // OneToMany bidirectional annotation i suppose
  // Do not forget ArrayCollection in constructor and addChild, removeChild and getChildren methods !
}

使用join子句创建自定义存储库:

// FamilyBundle\Repository\ParentRepository.php
namespace FamilyBundle\Repository;

use Doctrine\ORM\EntityRepository;

class ParentRepository extends EntityRepository
{
  public function findParents(array $criteria, array $orderBy = null)
  {
    $qb = $this
      ->createQueryBuilder('parent')
      ->leftJoin('parent.children', 'children') // join clause
      ->addSelect('children') // get children rows
    ;

    if (isset($criteria['some_data'])) // where clause example
    {
      $qb
        ->andWhere('children.some_data = :some_data') // andWhere clause works even if first where
        ->setParameter('some_data', $criteria['some_data'])
      ;
    }

    if (isset($orderBy['other_data'])) // orderBy clause example on Parent entity
    {
      $qb
        ->addOrderBy('parent.other_data', $orderBy['other_data']) // or orderBy clause
      ;
    }

    return $qb
      ->getQuery()
      ->getResult()
    ;
  }
}

在您的控制器中:

$parents = $this->getDoctrine()->getRepository('FamilyBundle:Parent')->findParents(
  array(
    'some_data' => 'dolor'
  ),
  array(
    'other_data' => 'DESC'
  )
);