подзапрос в соединении с доктриной dql

Я хочу использовать DQL для создания запроса, который выглядит следующим образом в SQL:

select
    e.*
from
    e
inner join (
    select
        uuid, max(locale) as locale
    from
        e
    where
        locale = 'nl_NL' or
        locale = 'nl'
    group by
        uuid
) as e_ on e.uuid = e_.uuid and e.locale = e_.locale

Я попытался использовать QueryBuilder для создания запроса и подзапроса. Я думаю, что они сами по себе делают правильные вещи, но я не могу объединить их в операторе соединения. Кто-нибудь сейчас, если это возможно с DQL? Я не могу использовать собственный SQL, потому что я хочу вернуть реальные объекты, и я не знаю, для какого объекта выполняется этот запрос (я знаю только базовый класс, у которого есть свойство uuid и locale).

    $subQueryBuilder = $this->_em->createQueryBuilder();
    $subQueryBuilder
        ->addSelect('e.uuid, max(e.locale) as locale')
        ->from($this->_entityName, 'e')
        ->where($subQueryBuilder->expr()->in('e.locale', $localeCriteria))
        ->groupBy('e.uuid');

    $queryBuilder = $this->_em->createQueryBuilder();
    $queryBuilder
        ->addSelect('e')
        ->from($this->_entityName, 'e')
        ->join('('.$subQueryBuilder.') as', 'e_')
        ->where('e.uuid = e_.uuid')
        ->andWhere('e.locale = e_.locale');

person Martijn de Munnik    schedule 31.10.2012    source источник
comment
Выполнение ВНУТРЕННЕГО СОЕДИНЕНИЯ для подзапроса - это именно то, что я пытаюсь сделать. Вы нашли решение?   -  person Chadwick Meyer    schedule 20.11.2014


Ответы (1)


Вы не можете поместить подзапрос в предложение FROM вашего DQL.

Я предполагаю, что ваш PK {uuid, locale}, на момент обсуждения с вами в IRC. Поскольку в вашем запросе также есть два разных столбца, это может стать некрасивым. Что вы можете сделать, так это поместить его в предложение WHERE:

select
    e
from
    MyEntity e
WHERE
    e.uuid IN (
        select
            e2.uuid
        from
            MyEntity e2
        where
            e2.locale IN (:selectedLocales)
        group by
            e2.uuid
    )
    AND e.locale IN (
        select
            max(e3.locale) as locale
        from
            MyEntity e3
        where
            e3.locale IN (:selectedLocales)
        group by
            e3.uuid
    )

Обратите внимание, что я использовал сравнение с (не пустым) массивом локалей, к которым вы привязываетесь к файлу :selectedLocales. Это сделано для того, чтобы избежать разрушения кеша запросов, если вы хотите сопоставить дополнительные локали.

Я также не предлагаю создавать это с помощью построителя запросов, если в этом нет реального преимущества, поскольку это просто упростит взлом кеша запросов, если вы добавляете условные операторы динамически (также задействовано 3 построителя запросов!)

person Ocramius    schedule 31.10.2012
comment
Я не думаю, что это сработает, потому что нет никакой связи между uuid и локалью для каждой строки в результате. - person Martijn de Munnik; 01.11.2012
comment
Да, ты прав... это не сработает. Можно concat поле uuid и locale и потом сделать проверку, но в таком случае любые ключи будут бесполезны (и это даже не очень хорошее решение) - person Ocramius; 01.11.2012