我有 2 个具有相同一对一关系的实体:
class FirstEntity {
...
/**
* @var AppEntityThirdEntity
*
* @ORMOneToOne(targetEntity="AppEntityThirdEntity")
*/
protected $thirdEntity;
class SecondEntity {
...
/**
* @var AppEntityThirdEntity
*
* @ORMOneToOne(targetEntity="AppEntityThirdEntity")
*/
protected $thirdEntity;
$thirdEntity
字段不能为空。 有没有办法通过查询生成器或本机查询(如 array_diff() 操作)返回结果:
$firsts = array_map(function (FirstEntity $firstEntity) {
return $firstEntity->getThirdEntity()->getId();
}, $this->em->getRepository(FirstEntity::class)->findAll());
$seconds = array_map(function (SecondEntity $secondEntity) {
return $secondEntity->getThirdEntity()->getId();
}, $this->em->getRepository(SecondEntity::class)->findAll());
return array_diff($firsts, $seconds);
所以我想要的是链接到FirstEntity
但不链接到SecondEntity
的所有ThirdEntity
的列表。
实现此目的的最高性能方法是使用本机查询或查询生成器(或多个本机查询/查询构建器)。这样,数据库将为您完成所有过滤,这意味着Doctrine不必做太多工作。
查询生成器是最简单的方法,但确实要求您还要求从ThirdEntity
映射到FirstEntity
并SecondEntity
- 以下代码假定您已经准备好了该映射。
$qb = $em->createQueryBuilder();
$result = $qb->select('t')->from('ThirdEntity', 't')
->innerJoin('t.firstEntity', 'f')
->leftJoin('t.secondEntity', 's')
->where($qb->expr()->isNull('s.id'));
->getQuery()->getResult();
这里发生的情况是,我们要求数据库获取所有ThirdEntity
记录,inner join
所有FirstEntity
记录(因此不包括没有FirstEntity
的ThirdEntity
)。然后我们用SecondEntity
left join
这一点,这意味着如果ThirdEntity
也链接到一个SecondEntity
,它的数据就可以过滤了,否则我们会得到所有SecondEntity
列的NULL
。最后一步是仅选择那些没有SecondEntity
的记录(这意味着其 ID 为null
)。
在确切的数据集上,这种"一个查询"方法可能无法为您提供最佳性能。首先选择与FirstEntity
相关的所有ThirdEntity
项的 ID,然后(在单独的查询中,在该查询中使用该 ID 列表作为参数)筛选出那些也与SecondEntity
相关的项可能会更快。反过来做这两件事也可能更快。不过我并不期待这一点,所以我们将把它留给另一个问题(或这个问题的另一个答案)。