3

我正在尝试优化查询,因为我需要一个简单的列表作为隶属于多个实体的实体。所以我创建了这个查询,你应该把 id 和 name 还给我:

public function findAllOrderByName() {
    $qb = $this->createQueryBuilder('a');
         $query = $qb->select(array('partial a.{id,name}'))
                 ->addOrderBy('a.name', 'ASC')
                 ->getQuery();

         return $query->getResult();
}

像这样在控制器中返回它:

public function getInstrumentsAction()
{
    $instruments = $this->getDoctrine()->getRepository('AcmeInstrumentBundle:Instrument')->findAllOrderByName();

    return array('instruments' => $instruments);
}

而不是只给我两个阵营,给我完整的对象,从而包括其他相关实体的所有领域。

为什么它不起作用?

4

1 回答 1

5

它实际上完全按照设计工作。您正在观察的是相关实体的延迟加载。

首先添加:

echo $query->getSQL() . "\n";
return $query->getResult();

你会看到类似的东西:

SELECT p0_.id AS id0, p0_.name AS name1 FROM instrument p0_ ORDER BY p0_.name ASC

因此,只有您要求的两个字段实际被查询。

echo sprintf("Instrument %s %s %s\n",
     $instrument->getName(),$instrument->getSomeotherScalervalue());

您会看到,虽然回显了名称,但即使它在仪器表中,也没有其他值。

就关系而言,让我们假设工具与人具有一对多关系。

$persons = $instrument->getPersons();

您可能会期望 $persons 是一个空数组,但它实际上是一个相当聪明的 Doctrine\ORM\PersistentCollection。一旦你尝试用 $person 做任何其他事情(甚至像 count($persons) 这样简单的事情,就会触发另一个查询,并且所有链接的 person 对象都将被加载。

这就是你所看到的。您实际上可以在您的日志/dev.log 中看到查询。只要您只是拉入仪器,那么只会生成一个查询。一旦您尝试对关系执行某些操作,就会出现另一个查询。

解决方法

  1. 不要试图访问关系。

  2. 在访问关系之前,您可以执行 $persons->setInitialized(true); 这将阻止加载。显然有点痛。

  3. 由于优化是您的目标,因此只需返回一个数组结果。根本没有对象。

  4. 您也可以继续在查询中加入您的关系,但使用 partial 来输入相关实体的 id。您的查询工作起来有点困难,但您不必担心会触发其他查询。

如果有某种方法可以防止基于查询的延迟加载,那就太好了。但如果有的话,我一直找不到。

于 2013-08-28T21:59:12.283 回答