dor2p0520 2016-03-27 23:21
浏览 82
已采纳

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

I have the following database structure (simplified). All relations are many to one.

table parent:

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

table child:

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

Using the normal doctrine method to display them all on a single page:

<?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>';
}

When using the debut tool, I was surprised to find out that in order to retrieve the child entities, a new database query is used for every parent entity. Resulting in a very inefficient script.

Above example is simplified. I could use a raw query if I weren't dependend on some specialised methods in the entity class. So my question is, is there a way to do a smarter query, but still be able to manage the data with the doctrine entity manager so that I can still access the entity class methods. Preferably, I would like to specify which children of the parent entity are preloaded, as I won't need to use all of them.

Anyone can point me in the right direction?

  • 写回答

1条回答 默认 最新

  • doujiayuan8415 2016-03-28 06:38
    关注

    Doctrine uses "lazy loading" by default if no join clause in query, so you have to create a custom repository class for your parent entity to reduce doctrine queries number.

    Just add repository annotation to your Parent entity class :

    // 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 !
    }
    

    And create your custom repository with join clause :

    // 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()
        ;
      }
    }
    

    In your controller :

    $parents = $this->getDoctrine()->getRepository('FamilyBundle:Parent')->findParents(
      array(
        'some_data' => 'dolor'
      ),
      array(
        'other_data' => 'DESC'
      )
    );
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 stm32开发clion时遇到的编译问题
  • ¥15 lna设计 源简并电感型共源放大器
  • ¥15 如何用Labview在myRIO上做LCD显示?(语言-开发语言)
  • ¥15 Vue3地图和异步函数使用
  • ¥15 C++ yoloV5改写遇到的问题
  • ¥20 win11修改中文用户名路径
  • ¥15 win2012磁盘空间不足,c盘正常,d盘无法写入
  • ¥15 用土力学知识进行土坡稳定性分析与挡土墙设计
  • ¥70 PlayWright在Java上连接CDP关联本地Chrome启动失败,貌似是Windows端口转发问题
  • ¥15 帮我写一个c++工程