假设相关实体不存在的选择实体

时间:2015-02-10 11:09:08

标签: php mysql orm doctrine-orm doctrine

我的实体(产品)与另一个名为 deletedByCompanies 的实体(公司)有多方向的单向关系。

我希望选择尚未被特定公司删除的所有产品。这就是所有通过这么多关系没有联系的产品。

尝试:

$this->em->getRepository(Product::class)->createQueryBuilder('t')
->leftJoin('t.deletedByCompanies', 'deletedCompany')
->andWhere('deletedCompany.id not in (:companyId)')
->setParameter('companyId', [$companyId]);

但这根本不会返回任何东西。 架构很简单:

Product:
   id: int PK

Company:
   id: int PK

DeletedProducts
   product_id: int FK
   company_id: int FK

Product class中的实体定义:

/**
 * @var Company[]
 * @ORM\ManyToMany(targetEntity="Company", indexBy="id")
 * @ORM\JoinTable(name="DeletedProducts")
 */
protected $deletedByCompanies;

2 个答案:

答案 0 :(得分:3)

我认为您可以使用deletedby表上的NOT EXISTS子句来解决您的问题。

在SQL方言中:

SELECT * FROM product p WHERE NOT EXISTS
 (SELECT * FROM DeletedProducts d WHERE p.id=d.product_id AND company_id = 2 );

在Doctrine2 DQL中,我们没有实体DeletedProducts所以我们必须做更多的事情,如:

$qb = $this->em->getRepository("AcmeDemoBundle:Product")->createQueryBuilder('t')
    ->Join('t.deletedByCompanies', 'deletedCompany')
    ->andWhere('deletedCompany.id  in (:companyId)')
    ->andWhere("p=t");

$mainQb = $this->em->getRepository("AcmeDemoBundle:Product")->createQueryBuilder('p');
$mainQb->where($mainQb->expr()->not($mainQb->expr()->exists($qb->getDQL())));
$mainQb->setParameter('companyId', [$companyId]);

var_dump($mainQb->getQuery()->getSql());
$res =$mainQb->getQuery()->execute();

如果我不明白你的问题,请告诉我。

希望这个帮助

答案 1 :(得分:2)

我不熟悉Doctrine,但我正在努力帮助学习一些SQL知识。以下查询应该执行您想要的操作:

SELECT DISTINCT Product.* FROM Product
LEFT JOIN DeletedProducts on product_id = product.id
WHERE product_id IS NULL OR product_id !=
    ALL( SELECT product_id FROM DeletedProducts WHERE company_id = 2 )

一些解释......

DISTINCT: Nessacary关键字可防止出现冗余。如果删除了左连接,则同一产品可能会多次出现。 DISTINCT 消除了这些重复项。

WHERE product_id为空: 左连接还将列出与“DeletedProducts”-table相关的任何公司无关的产品。由于没有关系,字段 product_id company_id NULL

OR product_id!= ALL([...]):现在我们已经获得了未被任何公司删除的产品,我们还需要那些未被删除的产品特别的公司。因此,我们使用带有子查询的 OR ,该子查询选择某个公司的所有已删除产品(例如公司ID = 2,如代码示例中所示)。由于我们希望拥有未删除的产品,因此我们必须使用“!=” - 运营商。

我希望这会有所帮助。现在由您来“翻译”Doctrine中的用法查询。