Внутреннее соединение по отношению "многие ко многим"

У меня есть эти 2 объекта в моем проекте Symfony: дом и программное обеспечение.

На многих домашних страницах может быть много программного обеспечения, а многие программы могут принадлежать многим домашним страницам.

Я пытаюсь получить только те дома, в которых есть, скажем, программное обеспечение №1 + программное обеспечение №2.

На самом деле мне удалось получить дома с программным обеспечением № 1 и с программным обеспечением № 2, но не с программным обеспечением 1 и программным обеспечением 2.

Если я не ошибаюсь, это должно быть внутреннее соединение, верно?

Вот мои объекты и метод репозитория:

    class Software {
          /**
           * @ORM\ManyToMany(targetEntity="App\Entity\Home", mappedBy="softwares")
           */
           private $homes;

           public function __constuct() {
               $this->homes = new ArrayCollection();
           }

           // ...

           public function getHomes(){ ... }
           public function addHome(Home $home){ ... }
           // ...

    }


    class Home {
          /**
           * @ORM\ManyToMany(targetEntity="App\Entity\Software", inversedBy="homes")
           */
           private $softwares;

           public function __constuct() {
               $this->softwares = new ArrayCollection();
           }

           //...

           public function getSoftwares(){ ... }
           public function addSoftware(Software $software){ ... }
           //...

    }

Домашний репозиторий

    class HomeRepository extends ServiceEntityRepository {
          public function innerJoinSoftware($softIds)
          {
               $qb = $this->createQueryBuilder('c')
                   ->innerJoin('c.softwares', 's')
                   ->andWhere('s.id IN(:softIds)')
                     ->setParameter('softIds', $softIds)
              ;
              return $qb->getQuery()->getResult();
         }
    }

Чтобы проиллюстрировать мою точку зрения:

  • В Home1 есть софт1, софт2

  • В Home2 есть софт1, софт3

  • В Home3 есть софт2, софт3

Я хочу сделать что-то вроде

  dump(homeRepo->innerJoinSoftware([1, 2]));
  //should output Home1 but actually I have
  //it outputs Home1, Home2, Home3

Вот версия SQL, с которой я вышел, но я все еще не могу сделать это с Doctrine

  SELECT home.id, home.name FROM Home as home
  INNER JOIN (
        SELECT home_id as home_id, COUNT(home_id) as count_home
        FROM home_software
        WHERE software_id IN (1, 2)
        GROUP BY home_id
        HAVING count_home = 2) as soft # count_home should be dynamic 
  ON home.id = soft.home_id
  ORDER BY home.name

person skytorner    schedule 06.09.2018    source источник
comment
Взгляните на этот ответ.   -  person ehymel    schedule 07.09.2018
comment
Я посмотрел ссылку, которую вы предоставили! Это действительно интересно! Я многое открыл! Но это не решает мою проблему: я не хочу получать программное обеспечение, но дома, чье программное обеспечение находится в списке, переданном в параметре   -  person skytorner    schedule 07.09.2018


Ответы (1)


Вот как я решаю эту проблему (помогает необработанный SQL, который я опубликовал)

public function findBySoftwaresIn($softIds)
{
    //retrieve nbr of soft per home
    $nbrSoftToFind = count($softIds);
    $qb = $this->createQueryBuilder('h');

    $qb->innerJoin('h.softwares', 's')
        ->andWhere('h.id IN (:softIds)')
            ->setParameter('softIds', $softIds)

        //looking for home coming back by nbrSoft
        ->andHaving($qb->expr()->eq($qb->expr()->count('h.id'), $nbrSoftToFind))
        ->groupBy('h.id')//dont forget to group by ID
        ->addOrderBy('h.name')
    ;

    return $qb->getQuery()->getResult();
}
person skytorner    schedule 14.09.2018