我的学说实体Section
具有自引用关联parent
和slug
属性。我创建了这个函数(在部分存储库中),用于返回给定其web路径的部分:
/**
* Finds a section by its path, i.e. /a/b/c.
*
* @param string $path
* @return null|\Application\Entity\Section
*/
public function findOneByPath($path)
{
// Slug exploding so we get array("a", "b", "c")
if (!($slugs = explode('/', $path))) {
return null;
}
// Get the slug for the leaf (at least) i.e. "c"
$leafSlug = array_pop($slugs);
// Query builder for selecting the leaf
$qb = $this->createQueryBuilder('s0');
$qb->select('s0')
->where($qb->expr()->eq('s0.slug', ':s0_slug'))
->setParameter('s0_slug', $leafSlug);
// Dynamical adding joins in reverse order i.e. array("b", "a")
$idx = 0;
foreach (array_reverse($slugs) as $slug) {
$qb->innerJoin("s{$idx}.parent", "s".++$idx)
->andWhere($qb->expr()->eq("s{$idx}.slug", ":s{$idx}_slug"))
->setParameter("s{$idx}_slug", $slug);
}
return $qb->getQuery()->getOneOrNullResult();
}
它工作正常,但我无法理解为什么 Doctrine正在进行两次查询(日志文件):
[2013-09-07 15:26:30] App.DEBUG: SELECT s0_.id AS id0, s0_.slug AS slug1 [...]
FROM section s0_ INNER JOIN section s1_ ON s0_.parent_id = s1_.id
WHERE (s0_.slug = ? AND s1_.slug = ?) ["b","a"] []
[2013-09-07 15:26:30] App.DEBUG: SELECT t0.id AS id1, t0.slug AS slug2 [...]
FROM section t0 WHERE t0.id = ? ["1"] []
正如你所看到的那样,第一个是INNER JOIN并且它是正确的。第二个是没用的,我想......或者我错过了什么?顺便说一下,1
是“a”的id
...
编辑:当foreach
未执行时(即findOneByPath('a')
),这种情况不会发生。有n + 1
次查询(n
不需要的)作为foreach
次迭代次数(/a/b/c/d
次4次查询)。
答案 0 :(得分:1)
在foreach中,您正在加入更多表,但是您没有将它们添加到SELECT子句中,这会导致N + 1查询情况。你需要在foreach中添加这样的东西:
$qb->addSelect('s' . $idx);