(Доктрина) Выбрать, где коллекция массивов не пуста? - PullRequest
0 голосов
/ 18 января 2019

У меня есть класс Сообщение:

/**
 * @ORM\Entity(repositoryClass="App\Repository\PostRepository")
 */
class Post
{
    const TYPE_TEXT   = 1;
    const TYPE_PHOTOS = 2;
    const TYPE_VIDEO  = 3;

    /**
     * @ORM\OneToMany(targetEntity="Photo", mappedBy="post")
     */
    private $photos;

    and other properties, methods, etc... 

И я хочу вернуть только те сообщения, в которых есть какие-либо фотографии.

У меня есть запрос DQL, такой как:

    $qb = $this->createQueryBuilder('p');
    $qb->select('p, postPhotos, etc...')
        ->leftJoin('p.photos', 'postPhotos')
        ->leftJoin('p.videos', 'postVideos')
        etc...

    if ($mediaType != null)
    {
        switch ($mediaType) {
            case Post::TYPE_PHOTOS:
                $qb->andWhere('postPhotos != :null')
                    ->setParameter('null', null);

"! =: Null" не работает, равно как и COUNT (postPhotos) (очевидно, по причинам агрегации).

Есть ли способ, который я могу указать только для того, чтобы вернуть посты с 1 или более фотографиями?

1 Ответ

0 голосов
/ 25 марта 2019

Быстрый ответ : Если вы замените использование leftJoin просто присоединением (или innerJoin), то вы получите то, что хотите: только сообщения, имеющие как минимум 1 фотографию.

Детали

Если вы посмотрите на этот полезный вопрос, вопросы и ответы:

Различные методы соединения MySQL

... вы найдете несколько превосходных диаграмм Венна, показывающих разницу между левым и внутренним соединением. Затем, если вы загляните в класс Doctrine Doctrine \ ORM \ QueryBuilder, вы обнаружите, что у них есть три метода соединения:

  • join (который просто вызывает innerJoin)
  • innerJoin
  • LeftJoin
    /**
     * Creates and adds a join over an entity association to the query.
     *
     * The entities in the joined association will be fetched as part of the query
     * result if the alias used for the joined association is placed in the select
     * expressions.
     *
     * <code>
     *     $qb = $em->createQueryBuilder()
     *         ->select('u')
     *         ->from('User', 'u')
     *         ->join('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
     * </code>
     *
     * @param string      $join          The relationship to join.
     * @param string      $alias         The alias of the join.
     * @param string|null $conditionType The condition type constant. Either ON or WITH.
     * @param string|null $condition     The condition for the join.
     * @param string|null $indexBy       The index for the join.
     *
     * @return self
     */
    public function join($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
    {
        return $this->innerJoin($join, $alias, $conditionType, $condition, $indexBy);
    }

    /**
     * Creates and adds a join over an entity association to the query.
     *
     * The entities in the joined association will be fetched as part of the query
     * result if the alias used for the joined association is placed in the select
     * expressions.
     *
     *     [php]
     *     $qb = $em->createQueryBuilder()
     *         ->select('u')
     *         ->from('User', 'u')
     *         ->innerJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
     *
     * @param string      $join          The relationship to join.
     * @param string      $alias         The alias of the join.
     * @param string|null $conditionType The condition type constant. Either ON or WITH.
     * @param string|null $condition     The condition for the join.
     * @param string|null $indexBy       The index for the join.
     *
     * @return self
     */
    public function innerJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
    {
        $parentAlias = substr($join, 0, strpos($join, '.'));

        $rootAlias = $this->findRootAlias($alias, $parentAlias);

        $join = new Expr\Join(
            Expr\Join::INNER_JOIN, $join, $alias, $conditionType, $condition, $indexBy
        );

        return $this->add('join', [$rootAlias => $join], true);
    }

    /**
     * Creates and adds a left join over an entity association to the query.
     *
     * The entities in the joined association will be fetched as part of the query
     * result if the alias used for the joined association is placed in the select
     * expressions.
     *
     * <code>
     *     $qb = $em->createQueryBuilder()
     *         ->select('u')
     *         ->from('User', 'u')
     *         ->leftJoin('u.Phonenumbers', 'p', Expr\Join::WITH, 'p.is_primary = 1');
     * </code>
     *
     * @param string      $join          The relationship to join.
     * @param string      $alias         The alias of the join.
     * @param string|null $conditionType The condition type constant. Either ON or WITH.
     * @param string|null $condition     The condition for the join.
     * @param string|null $indexBy       The index for the join.
     *
     * @return self
     */
    public function leftJoin($join, $alias, $conditionType = null, $condition = null, $indexBy = null)
    {
        $parentAlias = substr($join, 0, strpos($join, '.'));

        $rootAlias = $this->findRootAlias($alias, $parentAlias);

        $join = new Expr\Join(
            Expr\Join::LEFT_JOIN, $join, $alias, $conditionType, $condition, $indexBy
        );

        return $this->add('join', [$rootAlias => $join], true);
    }


Изменение вашего кода для использования innerJoin (или просто соединения) приведет к тому, что Doctrine выдаст INNER JOIN в сгенерированном SQL, который будет возвращать только записи, где «что-то» существует с обеих сторон соединения, таким образом, любая публикация, которая не имеет Фотографии не будут включены в результаты.

...