У меня есть два класса – Страница и 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), но есть ли какой-либо способ без этого или сделать его двунаправленным?
В 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 )
Другой способ заключается в дополнительном объединении с произвольной функциональностью объединения, введенной в версии 2.3 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
происходит только из-за ограничения тока синтаксического анализатора.
Обратите внимание, что ограничение, вызывающее семантическую ошибку, связано с тем, что процесс гидратации начинается с корня выбранных объектов. Без корня на месте, гидратор не имеет никаких указаний о том, как свернуть полученные или присоединенные результаты.
Я думаю, вам нужно также выбрать SiteVersion в вашем запросе:
SELECT v, p FROM SiteVersion v JOIN v.pages p WHERE v.id = 5 AND p.slug='index'
Вы получите массив объектов SiteVersion, которые вы можете пропустить, чтобы получить объекты страницы.
Я не мог понять, как работать с родными запросами, поэтому решил немного взлохмоло:
$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'
Попробуйте это (или что-то вроде этого):
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 Select Examples главы DQL.
Я нашел возможное решение этой проблемы.
Согласно этой странице, ваш запрос должен выглядеть примерно так:
SELECT p FROM SiteVersion v, Page p WHERE v.id = 5 AND p.slug='index' AND v.page = p;
Решает ли ваша проблема?