setMaxResults не работает нормально, когда запрос Doctrine имеет соединение - PullRequest
0 голосов
/ 06 мая 2018

Я хочу написать 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 (работает нормально)

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

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

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

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

В соответствии с Первый и Макс. Пункты результата

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

Что вы можете сделать, чтобы достичь желаемого, это использовать Paginator по вашему запросу:

$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 выше:

Запросы на страницы в доктрине не так просты, как вы могли подумать в начале. Если у вас есть сложные сценарии выборки-соединения с однозначными или многозначными связями, использование функциональности LIMIT «по умолчанию» поставщиков баз данных недостаточно для получения правильных результатов.

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

По умолчанию расширение пагинации выполняет следующие шаги для вычисления правильного результата:

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

Это поведение необходимо, только если вы на самом деле получаете присоединение к коллекции «многие». Вы можете отключить это поведение, установив для флага $ fetchJoinCollection значение false; в этом случае выполняется только 2 вместо 3 описанных запросов. Мы надеемся автоматизировать обнаружение этого в будущем.

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

0 голосов
/ 06 мая 2018

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

Вы, вероятно, должны запрашивать посты и теги отдельно и не использовать limit с отношениями "один ко многим" или "многие ко многим".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...