我有2个具有相同的一对一关系的实体:
class FirstEntity {
...
/**
* @var \App\Entity\ThirdEntity
*
* @ORM\OneToOne(targetEntity="App\Entity\ThirdEntity")
*/
protected $thirdEntity;
class SecondEntity {
...
/**
* @var \App\Entity\ThirdEntity
*
* @ORM\OneToOne(targetEntity="App\Entity\ThirdEntity")
*/
protected $thirdEntity;
$thirdEntity
字段无效。
有没有办法通过查询构建器或本机查询返回结果,如array_diff()opertion:
$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);
所以我想要的是与ThirdEntity
但不与FirstEntity
相关联的所有SecondEntity
的列表。
答案 0 :(得分:1)
执行此操作的最佳方法是使用本机查询或查询构建器(或多个本机查询/查询buidler)。这样,数据库将为您完成所有过滤,这意味着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
条记录一起使用(所以ThirdEntity
没有FirstEntity
}将不包括在内)。然后我们left join
使用SecondEntity
,这意味着如果ThirdEntity
也与SecondEntity
相关联,则其数据可用于过滤,否则我们会获得NULL
对于所有SecondEntity
列。最后一步是仅选择那些没有SecondEntity
的记录(意思是其ID为null
)。
取决于确切的数据集,这种“一个查询”方法可能无法为您提供最佳性能。 可以更快地首先选择与ThirdEntity
有关系的所有FirstEntity
项的ID然后(在单独的查询中,您使用该ID列表作为参数)过滤掉那些与SecondEntity
有关系的项目。反过来做这两件事也可能更快。我不是没想到的,所以我们会把它留给另一个问题(或者这个问题的另一个答案)。