Подтвердить что ты не робот

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

Такой запрос приводит к ошибке:

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

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

Я также пробовал

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

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

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

Любые идеи?

4b9b3361

Ответ 1

Как сказал Мэтт, это старая проблема, которую Doctrine Project не будет исправлять (DDC-16).

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

Мы думали о том, чтобы разрешить повышение рейтинга пару раз, но попытка получить эту работу просто не стоит того, и люди просто злоупотребляют синтаксисом, делая очень опасные вещи.

Как указано в DDC-16, также невозможно понять, к какому классу принадлежит свойство, не подвергая себя неприятным проблемам, таким как несколько подклассов, определяющих одни и те же свойства с разными именами столбцов.

Если вы хотите отфильтровать данные в подклассах в CTI или JTI, вы можете использовать технику, описанную мной в fooobar.com/questions/286873/.... Это связывает ваш 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 очень разные и следуют различным правилам.

Ответ 3

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

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

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

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


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

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

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

SELECT     r FROM     Корень r ГДЕ     r.id IN (         ВЫБРАТЬ             c.id         ИЗ             Ребенок c         ГДЕ             c.field =: значение     )

Ответ 4

Вы можете легко решить это, объединив свой базовый объект с вашим классом наследования с помощью 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');

Это основано на ответе Йан Филипса в вопросе здесь

Ответ 5

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

Одно я уверен, одно наследование таблицы не решит это, совершенно одно и то же.

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