Доктрина DQL, наследование таблиц классов и доступ к полям подкласса - PullRequest
18 голосов
/ 14 декабря 2011

У меня проблема с DQL-запросом и специализацией сущностей.

У меня есть сущность с именем 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 ...". 

Такой запрос приводит к ошибке, говорящей, что:

Класс Entities\Item не имеет поля или ассоциации с именем bookTypes

, что ложно для Book, но верно для Item.

я тоже пробовал

SELECT a FROM Entities\Book i 
    INNER JOIN i.auction a ...

но я считаю, что Doctrine требует, чтобы я ссылался на одну и ту же сущность в операторах SELECT и FROM.

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

Есть идеи?

Ответы [ 5 ]

10 голосов
/ 20 января 2014

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

4 голосов
/ 07 августа 2013

Обновлен:

Я нашел решение для этого. Смотрите мой ответ на этот связанный вопрос:

Doctrine2: Полиморфные Запросы: Поиск свойств подклассов

2 голосов
/ 09 марта 2015

Вы можете легко решить эту проблему, присоединив левую базовую сущность к вашему классу наследования, используя идентификатор:

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...

или с запросом Builder:

$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 голосов
/ 13 ноября 2013

Команда Doctrine заявила, что не собирается добавлять поддержку для этого:

http://www.doctrine -project.org / jira / browse / DDC-16

Соответствующие комментарии с этой страницы:

Это действительно сложно.Однако один только этот синтаксис может никогда не сработать, потому что может быть несколько подклассов с полем с именем «d», поэтому Doctrine не будет знать, какое поле вы имеете в виду.


Я закрываю этот.

Требование этой проблемы в основном нарушает принципы ОО.

Если вам действительно нужно фильтровать по нескольким дочерним объектам в вашем наследовании, тогда попробуйте что-то вроде следующего вместо:

SELECT r ИЗ Root r, ГДЕ r.id IN (ВЫБРАТЬ c.id ИЗ ДЕТАЛЯ c, ГДЕ c.field =: значение)

0 голосов
/ 22 декабря 2011

У меня была та же проблема, и я не нашел решения без использования отдельных запросов для каждого подкласса и их последующего объединения на уровне приложения.

В одном я уверен, что наследование одной таблицы не решит этого, совершенно то же самое.

Есть другая альтернатива, хотя она и логически грязная. Определите все поля (те, которые вам нужны) в суперклассе. Если запись логически не имеет этого поля, она будет пустой. Не симпатичное зрелище, но эй, более оптимизированное, чем 2-3-4 -... запросы. Также в этом сценарии наследование одной таблицы определенно является лучшим способом

...