ОБЪЕДИНЕНИЕ Doctrine DQL

#php #join #orm #doctrine-orm #dql

#php #Присоединиться #orm #doctrine-orm #dql

Вопрос:

У меня есть следующие объекты, сопоставленные с Doctrine 2:

 class Zone
{
    /**
     * @ManyToOne(targetEntity="Zone", inversedBy="children")
     * @var Zone
     */
    protected $parent;

    /**
     * @OneToMany(targetEntity="Zone", mappedBy="parent")
     * @var Zone[]
     */
    protected $children;

    /**
     * @ManyToMany(targetEntity="Zone")
     * @var Zone[]
     */
    protected $descendants;
}

class Restaurant
{
    /**
     * @ManyToOne(targetEntity="Zone")
     * @var Zone
     */
    protected $zone;
}
 

По сути, у зоны есть родительский элемент и, следовательно, дочерние элементы. Поскольку дочерние элементы могут сами иметь дочерние элементы, каждая зона также хранит список всех своих потомков.

Каждому ресторану назначается зона.

Что я хочу сделать, так это выполнить объединение DQL, чтобы вернуть все рестораны в определенной зоне (включая всех ее потомков).

Если бы мне пришлось делать это в обычном SQL, я бы написал:

 SELECT r.* from Zone z
JOIN ZoneDescendant d ON d.zoneId = z.id
JOIN Restaurant r ON r.zoneId = d.descendantId
WHERE z.id = ?;
 

Возможно ли это сделать с помощью Doctrine DQL, не добавляя $restaurants свойство в зону и не усложняя бесполезно модель предметной области?

Ответ №1:

Хорошо, я, наконец, нашел способ сделать это только с помощью объединений (значительно быстрее в MySQL):

 SELECT r
FROM Restaurant r,
     Zone z
JOIN z.descendants d
WHERE r.zone = d
AND z = ?1;
 

Комментарии:

1. Да, это намного лучше, рад, что вы нашли лучшее решение! Хорошая идея 🙂

Ответ №2:

Единственный способ, которым я могу придумать, как сделать это в одном запросе DQL, — использовать подзапрос:

 SELECT r FROM Restaurant r WHERE r.zone IN (SELECT zc.id FROM r.zone z JOIN z.children zc WHERE z.id = :zoneId) OR r.zone = :zoneId
 

Комментарии:

1. Эта идея работает, спасибо! Однако у меня есть несколько проблем с производительностью. Я использую MySQL 5.6.3 m6, который по-прежнему не переписывает эти подзапросы как объединения и резко замедляется при выполнении этих запросов. Я думаю, что наиболее эффективным решением может быть создание ZoneRestaurants представления, выполняющего соответствующее объединение, затем включение «поддельного» (неиспользуемого в классе) $restaurants свойства в зону и сопоставление этого свойства с @ManyToMany использованием представления ZoneRestaurants в качестве таблицы соединений.