У меня проблема с DQL-запросом и специализацией.
У меня есть Entity, называемый Auction
, который является отношением OneToOne
к Item
. Item
– это mappedSuperclass
для Film
и Book
. Мне нужен запрос, который мог бы помочь поисковой системе, позволяя пользователю искать аукционы с разными свойствами AND
продавать предметы с разными свойствами (это часть AND
что делает ее сложной).
Проблема в том, что, хотя у Auction
есть ассоциация, указывающая на Item
как таковой, мне нужно иметь доступ к полям Film
и Book
. Пользователи будут указывать тип Item
они ищут, но я не вижу никакого способа использовать эту информацию, кроме использования INSTANCE OF
в моем DQL-запросе.
До сих пор я пытался использовать такой запрос, как:
SELECT a FROM Entities\Auction a INNER JOIN a.item i INNER JOIN i.bookTypes b WHERE i INSTANCE OF Entities\Book AND b.type = 'Fantasy' AND ...".
Такой запрос приводит к ошибке:
bookTypes
классаEntities\Item
не имеет поля или ассоциации с именемbookTypes
что неверно для Book
, но верно для Item
.
Я также пробовал
SELECT a FROM Entities\Book i INNER JOIN i.auction a ...
но я считаю, что доктрина требует, чтобы я ссылался на те же сущности в SELECT
и FROM
.
Если это важно, я использую наследование таблицы классов. Тем не менее, я не думаю, что переход на одно наследование таблицы может сделать трюк.
Есть идеи?
Как сказал Мэтт, это старая проблема, которую Doctrine Project не будет исправлять ( DDC-16 ).
Проблема в том, что DQL доктрины – это статически типизированный язык, который имеет определенную сложность во внутренних деталях.
Мы думали о том, что пару раз повышаем рейтинг, но попытка получить эту работу просто не стоит того, и люди просто злоупотребляют синтаксисом, делая очень опасные вещи.
Как указано в DDC-16, также невозможно понять, к какому классу принадлежит свойство, не подвергая себя неприятным проблемам, таким как несколько подклассов, определяющих одни и те же свойства с разными именами столбцов.
Если вы хотите отфильтровать данные в подклассах в CTI или JTI, вы можете использовать технику, описанную мной на https://stackoverflow.com/a/14854067/347063 . Это сопрягает ваш DQL со всеми вовлеченными подклассами.
Вероятно, вам понадобится DQL в вашем случае (предполагая, что Entities\Book
является подклассом Entities\Item
):
SELECT a FROM Entities\Auction a INNER JOIN a.item i INNER JOIN i.bookTypes b WHERE i.id IN ( SELECT b.id FROM Entities\Book b WHERE b.type = 'Fantasy' )
Это псевдокод для вашей проблемы. Это не приятно, но имейте в виду, что SQL и DQL очень разные и соответствуют различным правилам.
Обновлено:
Я нашел решение для этого. См. Мой ответ на этот связанный вопрос:
Doctrine2: Полиморфные запросы: поиск по свойствам подклассов
Команда Doctrine заявила, что они не собираются добавлять поддержку для этого:
http://www.doctrine-project.org/jira/browse/DDC-16
Соответствующие комментарии с этой страницы:
Это действительно сложно. Однако этот синтаксис никогда не может работать, потому что может быть несколько подклассов, у которых есть поле с именем «d», поэтому Doctrine не знает, какое поле вы имеете в виду.
Я закрываю это.
Требование этой проблемы в основном нарушает принципы ОО.
Если вам действительно нужно отфильтровать несколько дочерних объектов в вашем наследовании, попробуйте следующее:
SELECT r FROM Root r WHERE r.id IN (SELECT c.id FROM Child c WHERE c.field =: значение)
Вы можете легко решить это, присоединив ваш базовый объект к вашему классу наследования с помощью id:
SELECT a FROM Entities\Auction a INNER JOIN a.item i INNER JOIN Entities\Book b WITH b.id = i.id INNER JOIN b.bookTypes bt WHERE bt.type = 'Fantasy' AND...
или с queryBuilder:
$queryBuilderb->select('a') ->from('Entities\Auction', 'a') ->innerJoin('a.item', 'i') ->innerJoin('Entities\Book', 'b', 'WITH', 'b.id = i.id') ->innerJoin('b.bookTypes', 'bt') ->where('bt.type = :type') ->andWhere(... ->setParameter('type', 'Fantasy');
Это основано на ответе Йан Филипса на вопрос здесь
У меня была та же проблема, и я не нашел решения без использования отдельных запросов для каждого подкласса и слияния их позже на уровне приложения.
Одно я уверен, одно наследование таблицы не решит этого, совершенно одно и то же.
Существует еще одна альтернатива, хотя и логически грязная. Определите все поля (те, которые вам нужны) в суперклассе. Если запись логически не имеет этого поля, она будет пустой. Не красивое зрелище, но эй, более оптимизированное, чем 2-3-4 -… запросы. Кроме того, в этом случае однонаправленное наследование таблицы, безусловно, лучший способ пойти