SetMaxResults не работает нормально, когда запрос Doctrine имеет соединение

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

Вот мой код:

   $dql = '
                    SELECT p , h ,t ,m 
                    FROM App:Post p 
                    LEFT JOIN p.mentions m
                    LEFT JOIN p.tags t 
                    LEFT JOIN p.file h 
                    WHERE p.user
                    IN (
                        SELECT f FROM App:User u
                        JOIN u.followers f
                        WHERE u.id = :uid
                       )
                    OR p.user = :uid ';

    $query = $this->getEntityManager()
        ->createQuery($dql)
        ->setMaxResults(5)
        ->setParameters(['uid' => $user->getId()])
        ->getArrayResult();

Но проблема в том, что setMaxResults не ограничивает Entity сообщений, а вместо этого ограничивает теги Entity на 5.

Вот мои два типа результатов:

1. с setMaxResults (не работает нормально)

2. с setMaxResults (работает нормально)

Что не так с моим кодом?

нет setMaxResults ограничивает теги @Aurelien

mR.Rian 06.05.2018 15:04
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
8
1
5 394
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я предлагаю запустить этот запрос (с ограничением) напрямую в БД. Вы увидите, что запрос возвращает 5 строк, но только с 3 уникальными сообщениями. Это связано с тем, что в одном сообщении может быть несколько тегов, поэтому каждая комбинация пост-тегов приведет к одной строке. Таким образом, 2 сообщения с 3 тегами в каждом будут содержать 6 строк. Установка лимита повлияет на количество строк, возвращаемых запросом, но не ограничивает магическим образом только количество сообщений. Дублированные сообщения в результате запроса удаляются при сопоставлении результата запроса с объектами, но на данный момент у вас есть только 3 уникальных сообщения.

Вероятно, вам следует запрашивать сообщения и теги отдельно и не использовать limit с отношениями «один-ко-многим» или «многие-многие».

Ответ принят как подходящий

Это ожидаемое поведение в доктрине при использовании setMaxResults () или setFirstResult () без пагинатора.

setMaxResults () фактически добавляет ПРЕДЕЛ SQL к произведенному запросу, он не ограничивает только корневую сущность, как вы ожидаете, но строки, возвращаемые запросом. Это означает, что по объединенным запросам он не будет делать то, что вы хотите.

По данным Элементы первого и максимального результатов

If your query contains a fetch-joined collection specifying the result limit methods are not working as you would expect. Set Max Results restricts the number of database result rows, however in the case of fetch-joined collections one root entity might appear in many rows, effectively hydrating less than the specified number of results.

Что вы можете сделать для достижения желаемого, так это использовать Пагинатор в своем запросе:

$query = $this->getEntityManager()
    ->createQuery($dql)
    ->setMaxResults(5)
    ->setParameters(['uid' => $user->getId()]);
$paginator = new Paginator($query, $fetchJoinCollection = true);

$c = count($paginator);
foreach ($paginator as $post) {

}

Из ссылки на документацию Paginator выше:

Paginating Doctrine queries is not as simple as you might think in the beginning. If you have complex fetch-join scenarios with one-to-many or many-to-many associations using the "default" LIMIT functionality of database vendors is not sufficient to get the correct results.

Также обратите внимание, что:

By default the pagination extension does the following steps to compute the correct result:

  • Выполните запрос Count, используя ключевое слово DISTINCT.
  • Выполните предельный подзапрос с DISTINCT, чтобы найти все идентификаторы объекта на текущей странице.
  • Выполните запрос WHERE IN, чтобы получить все результаты для текущей страницы.

This behavior is only necessary if you actually fetch join a to-many collection. You can disable this behavior by setting the $fetchJoinCollection flag to false; in that case only 2 instead of the 3 queries described are executed. We hope to automate the detection for this in the future.

Аналогичный вопрос

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

mR.Rian 07.05.2018 07:04

@ mR.Rian. Возможно, у вас есть круговая ссылка, например, Post -> Tags -> Posts, которая используется при сериализации, но для этого, я думаю, вам следует задать новый вопрос.

Jannes Botis 07.05.2018 11:30

Это отличный ответ. Спасибо

Miles M. 22.07.2020 18:46

Другие вопросы по теме