【问题标题】:Doctrine generates huge amount of queries to display entities with child entitiesDoctrine 生成大量查询以显示具有子实体的实体
【发布时间】:2016-03-27 23:21:19
【问题描述】:

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

父表:

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

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

上面的例子是简化的。如果我不依赖实体类中的某些专门方法,我可以使用 原始查询所以我的问题是,有没有办法进行更智能的查询,但仍然能够使用学说实体管理器管理数据,以便我仍然可以访问实体类方法。 最好,我会喜欢指定预加载父实体的哪些子实体,因为我不需要使用所有子实体。

谁能指出我正确的方向?

【问题讨论】:

  • 使用查询构建器或 DQL 查询来获取您需要的实体,您在查询中加入的关系将被加载,这样您就可以避免在循环中延迟加载等问题。

标签: php symfony doctrine-orm doctrine


【解决方案1】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 2013-04-07
    • 1970-01-01
    • 2016-12-02
    • 2020-01-09
    相关资源
    最近更新 更多