Php 条令生成大量查询以显示具有子实体的实体

Php 条令生成大量查询以显示具有子实体的实体,php,symfony,doctrine-orm,doctrine,Php,Symfony,Doctrine Orm,Doctrine,我简化了以下数据库结构。所有的关系都是多对一的 表父项: 表儿童: 使用普通条令方法在单个页面上显示所有条令: <?php //get parents $parents = $this->getDoctrine()->getRepository('FamilyBundle:Parent')->findAll(); //loop through parents foreach($parents AS $parent){ //display parent echo

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

表父项:

表儿童:

使用普通条令方法在单个页面上显示所有条令:

<?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实体管理器管理数据,这样我仍然可以访问实体类方法。最好,我想指定预加载父实体的哪些子实体,因为我不需要全部使用它们


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

如果查询中没有join子句,则默认情况下,条令使用延迟加载,因此您必须为父实体创建自定义存储库类以减少条令查询数

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

// 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'
  )
);

如果查询中没有join子句,则默认情况下,条令使用延迟加载,所以您必须为父实体创建自定义存储库类,以减少条令查询数

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

// 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'
  )
);

使用查询生成器或DQL查询获取所需的实体,将加载您在查询中加入的关系,以避免在循环等中出现延迟加载问题。使用查询生成器或DQL查询获取所需的实体,您在查询中加入的关系将被加载,因此您可以避免在循环等中看到的延迟加载问题。