我有以下数据库结构(简化)。所有关系都是多对一。
表格父级:
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实体管理器管理数据,这样我仍然可以访问实体类方法。最好,我会喜欢指定父实体的哪些子项被预加载,因为我不需要使用它们。
任何人都可以指出我正确的方向吗?
答案 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'
)
);