我有一个产品实体,它与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);
答案 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=1
和id=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中过滤结果,我对此犹豫不决认为存在性能缺陷。