Symfony2 - Doctrine2 QueryBuilder WHERE IN ManyToMany field


Symfony2 - Doctrine2 QueryBuilder WHERE IN ManyToMany field

:)

提前感谢您帮助我解决这个问题:

我有一家实体酒店,它与一家实体HotelService 有ManyToMany关系

我如何构建(如果可能的话,使用QueryBuilder)一个查询来选择所有拥有作为数组参数的服务子集的酒店?

示例:H1(S1、S2、S3、S4)、H2(S2、S3和S4)、H3(S1、S3和S3)

查询子集(S1、S2)必须返回H1和H3。

我试过很多东西,这是一些代码摘录:

public function findByServices($services) {
 
    $qb = $this->createQueryBuilder('hotel')
 
            ->addSelect('location')
 
            ->addSelect('country')
 
            ->addSelect('billing')
 
            ->addSelect('services')
 
            ->innerJoin('hotel.billing', 'billing')
 
            ->innerJoin('hotel.location', 'location')
 
            ->innerJoin('location.city', 'city')
 
            ->innerJoin('location.country', 'country');
 
            ->innerJoin('hotel.services', 'services');
 
    $i = 0;
    $arrayIds = array();
    foreach ($services as $service) {
        $arrayIds[$i++] = $service->getId();
    }
    $qb->add('where', $qb->expr()->in('services', $arrayIds))->getQuery();
}

此代码返回$arrayId中有一个服务id的所有酒店。

我想要相反的(服务在$arrayId中包含所有id的酒店)。

当然,在expr()->in中反转参数并不能解决问题,还会产生坏的参数错误。

有人能帮帮我吗?(抱歉我英语不好):)

对于您的解决方案,您可以使用带有HAVINGGROUP BY子句的COUNT(DISTINCT)

public function findByServices($services)
{
    $qb = $this->createQueryBuilder('hotel')
        ->addSelect('location')
        ->addSelect('country')
        ->addSelect('billing')
        ->addSelect('services')
        ->addSelect('COUNT(DISTINCT  services.id) AS total_services')
        ->innerJoin('hotel.billing', 'billing')
        ->innerJoin('hotel.location', 'location')
        ->innerJoin('location.city', 'city')
        ->innerJoin('location.country', 'country')
        ->innerJoin('hotel.services', 'services');
    $i = 0;
    $arrayIds = array();
    foreach ($services as $service) {
        $arrayIds[$i++] = $service->getId();
    }
    $qb->add('where', $qb->expr()->in('services', $arrayIds))
        ->addGroupBy('hotel.id')
        ->having('total_services = '.count($arrayIds))
        ->getQuery();
}

在上面的查询中,我又添加了一个选项,用于计算每个酒店的不同服务ID,即

->addSelect('COUNT(DISTINCT services.id)AS HIDDEN total_services')

然后我还需要一个分组,所以我添加了

->addGroupBy('hotel.id')


现在来了一个棘手的部分,正如你提到的,你需要拥有所有服务ID的酒店,比如ID(1,2,3),所以当我们在执行或操作中使用where servid_id = 1 or servid_id = 2 servid_id = 3时,包含这3个服务的酒店应该被返回,这正是你不想要酒店必须拥有这3个的AND操作,所以我通过拥有部分来转换这个逻辑

->具有('total_services='.count($arrayId))

现在total_services是查询的虚拟别名,并保存每个酒店的不同计数,因此我将此计数与IN()部分中提供的ID的计数进行了比较,这将返回必须包含这些服务的酒店


GROUP BY and HAVING Clause