Doctrine DQL, наследование таблицы классов и доступ к полям подкласса

У меня проблема с 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 .

Если это важно, я использую наследование таблицы классов. Тем не менее, я не думаю, что переход на одно наследование таблицы может сделать трюк.

Есть идеи?

Related of "Doctrine DQL, наследование таблицы классов и доступ к полям подкласса"

Как сказал Мэтт, это старая проблема, которую 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 -… запросы. Кроме того, в этом случае однонаправленное наследование таблицы, безусловно, лучший способ пойти