Doctrine ManyToMany查询

时间:2014-04-04 20:57:41

标签: symfony doctrine-orm dql

我有一个产品实体,它与Taxon实体具有ManyToMany关系。我想找到所有属于所有分类的交集的产品。例如,我想查找属于ID为1和2的分类单元的所有产品。

Products
{1,2,3}

Taxons
{1,2,3,4,5}

ProductsToTaxons
{{p1,t1},{p1,t2}, {p2,t2}}

我想在查询分类单元1和2的产品时检索以下设置:

Product
{1} 
which is from {{p1,t1}, {p1,t2}}

好的,所以这是我尝试的DQL ......但它不起作用?

SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t 
WHERE t.id = 1 AND t.id = 2

(P.S。我也会用QueryBuilder也这样做)

修改

为了澄清,这里是我想要转换为DQL / QueryBuilder的SQL。

select p.id 
from product p 
where exists (select product_id 
              from product_to_taxon 
              where taxon_id = 1 
              and product_id = p.id) 
and exists (select product_id 
            from product_to_taxon 
            where taxon_id = 4 
            and product_id = p.id);

4 个答案:

答案 0 :(得分:4)

您可以使用MEMBER OF语句来实现此目的,但根据我的经验,它没有使用ManyToMany关系产生非常高效的结果: 在DQL中:

SELECT p FROM SRCProductBundle:Product p
WHERE 1 MEMBER OF p.taxons OR 2 MEMBER OF p.taxons

或使用“查询”构建器

$this->createQueryBuilder('p')
    ->where(':taxon_ids MEMBER OF p.taxons')
    ->setParameter('taxon_ids', $taxonIdsArray)
    ->getQuery()
    ->getResult();

这将创建类似于提供的示例的SQL,尽管根据我的经验,它仍然在EXISTS子查询中有一个连接。也许未来版本的Doctrine可以解决这个问题。

答案 1 :(得分:1)

我想你想要这样的东西:

    $qb = $this
        ->createQueryBuilder('p')
        ->select('p.id')
    ;
    $qb
        ->leftJoin('p.taxons', 'taxon1', Join::WITH, 'taxon1.id = :taxonId1')
        ->setParameter('taxonId1', 1)
        ->andWhere($qb->expr()->isNotNull('taxon1'))
        ->leftJoin('p.taxons', 'taxon2', Join::WITH, 'taxon2.id = :taxonId2')
        ->setParameter('taxonId2', 2)
        ->andWhere($qb->expr()->isNotNull('taxon2'))
    ;

这相当于SQL:

SELECT p.id
  FROM products p
  LEFT JOIN taxons t1 ON (p.id = t1.product_id AND t1.id = 1)
  LEFT JOIN taxons t2 ON (p.id = t2.product_id AND t2.id = 2)
 WHERE t1.id IS NOT NULL
   AND t2.id IS NOT NULL
;

答案 2 :(得分:0)

您的DQL逻辑错误。您不能同时拥有id=1id=4的分类单元。你可以这样做:

SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t 
WHERE t.id = 1 OR t.id = 4

但我更喜欢这样:

SELECT p FROM SRCProductBundle:Product p
JOIN p.taxons t 
WHERE t.id IN (1, 4)

使用看起来像这样的查询构建器,假设您在EntityRepository类中:

$this->createQueryBuilder('p')
    ->join('p.taxons', 't')
    ->where('t.id IN :taxon_ids')
    ->setParameter('taxon_ids', $taxonIdsArray)
    ->getQuery()
    ->getResult();

答案 3 :(得分:0)

由于缺乏使用DQL执行此操作的简洁方法,经过大量研究后,我在Native SQL中执行此操作。 Doctrine allows Native SQL通过带有createNativeQuery()的EntityManager。

简而言之,我利用这种能力并将我的问题中包含的SQL查询构造为一个字符串,然后将其传递给createNativeQuery()函数。

这似乎有一些缺点,因为看起来我将无法使用它的KnpPaginatorBundle ...所以我可能最终只是在PHP而不是SQL中过滤结果,我对此犹豫不决认为存在性能缺陷。