代码之家  ›  专栏  ›  技术社区  ›  jspizziri

Doctrine ManyToMany查询

  •  3
  • jspizziri  · 技术社区  · 12 年前

    我有一个产品实体,它与Taxon实体有很多关系。我想找到属于所有紫杉醇交集的所有产品。例如,我想查找属于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
    

    (注:我也会使用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 回复  |  直到 12 年前
        1
  •  4
  •   David Stone    10 年前

    您可以使用 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子查询中有一个连接。也许未来版本的学说可以解决这个问题。

        2
  •  1
  •   caponica    9 年前

    我想你想要这样的东西:

        $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
    ;
    
        3
  •  0
  •   Igor Pantović    12 年前

    你的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();
    
        4
  •  0
  •   jspizziri    12 年前

    由于缺乏一种用DQL实现这一点的干净方法,并且经过大量的研究,我求助于用Native SQL实现这一目标。 Doctrine allows Native SQL 通过带有createNativeQuery()的EntityManager。

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

    这看起来确实有一些缺点,因为我似乎无法将KnpPaginatorBundle与它一起使用……所以我可能最终只会用PHP而不是SQL过滤结果,因为我认为存在性能缺点,所以我很犹豫是否要这样做。