我有两个类--Page和SiteVersion,它们有很多关系。只有SiteVersion知道这种关系(因为该网站是模块化的,我希望能够带走并放入SiteVersion所属的模块)。
我如何根据SiteVersion的标准选择页面?
例如,这不起作用:
SELECT p FROM SiteVersion v JOIN v.pages p WHERE v.id = 5 AND p.slug='index'
我收到错误:
[Doctrine\ORM\Query\QueryException]
[Semantical Error] line 0, col -1 near 'SELECT p FROM': Error: Cannot select entity through identification variables without choosing at least one root entity alias.
即使我可以使用此查询选择“v”。
我想我可以通过引入一个关系类(一个PageToVersion类)来解决这个问题,但有没有办法不这样做,或者让它成为双向的?
答案 0 :(得分:24)
在Doctrine ORM中有两种处理方法。最典型的是使用带有子查询的IN
条件:
SELECT
p
FROM
SitePage p
WHERE
p.id IN(
SELECT
p2.id
FROM
SiteVersion v
JOIN
v.pages p2
WHERE
v.id = :versionId
AND
p.slug = :slug
)
另一种方法是使用arbitrary join functionality introduced in version 2.3 of the ORM进行额外加入:
SELECT
p
FROM
SitePage p
JOIN
SiteVersion v
WITH
1 = 1
JOIN
v.pages p2
WHERE
p.id = p2.id
AND
v.id = :versionId
AND
p2.slug = :slug
1 = 1
只是因为解析器的当前限制。
请注意the limitation that causes the semantical error是因为水化过程从所选实体的根开始。如果没有根,水化器就没有关于如何折叠fetch-joined或加入结果的参考。
答案 1 :(得分:2)
我认为您还需要在查询中选择SiteVersion:
SELECT v, p FROM SiteVersion v JOIN v.pages p WHERE v.id = 5 AND p.slug='index'
您将获得一组SiteVersion实体,您可以循环访问这些实体以获取Page实体。
答案 2 :(得分:1)
我无法弄清楚如何让原生查询正常工作,所以我们已经解决了一些问题:
$id = $em->getConnection()->fetchColumn("SELECT
pages.id
FROM
pages
INNER JOIN siteversion_page ON siteversion_page.page_id = pages.id
INNER JOIN siteversions ON siteversion_page.siteversion_id = siteversions.id
WHERE siteversions.id = 1
AND pages.slug = 'index'");
$page = $em->find('Page', $id);
我不喜欢它,因为它会导致对数据库的更多查询(特别是如果我需要获取一个页面数组而不是一个),但它可以工作。
编辑:我决定只参加一个关联课程。现在我可以做这个查询:
SELECT p FROM Page p, SiteVersionPageLink l
WHERE l.page = p AND l.siteVersion = 5 AND p.slug = 'index'
答案 3 :(得分:1)
试试这个(或类似的东西):
SELECT p FROM Page p WHERE EXISTS (SELECT v FROM SiteVersion v WHERE p MEMBER OF v.pages AND v.id = 5 AND p.slug = 'index')
我没有完全测试过这个,但是我得到了类似的东西。 EXISTS
和MEMBER OF
的使用隐藏在DQL章节的DQL Select Examples部分。
答案 4 :(得分:0)
我找到了解决此问题的可能方案here。
根据该页面,您的查询应如下所示:
SELECT p FROM SiteVersion v, Page p WHERE v.id = 5 AND p.slug='index' AND v.page = p;
它能解决你的问题吗?