查找具有所有匹配值的关系集合的实体



在我的Symfony项目中,我有一个" exercicecomptable ";和"文档出席";实体。在ExerciceComptable中有一个引用DocumentAttendu (OneToMany)的关系。在DocumentAttendu中,我有一个名为"recu"的属性。这是一个布尔值

我需要检索所有的"exercicecomptable";,这意味着所有的"DocumentAttendu"对于一个"练习题";拥有财产"征召";设置为true

我该怎么做呢?

ExerciceComptable

#[ORMOneToMany(mappedBy: 'exercice', targetEntity: DocumentAttendu::class)]
private Collection $documentAttendus;
/**
* @return Collection<int, DocumentAttendu>
*/
public function getDocumentAttendus(): Collection
{
return $this->documentAttendus;
}
public function addDocumentAttendu(DocumentAttendu $documentAttendu): self
{
if (!$this->documentAttendus->contains($documentAttendu)) {
$this->documentAttendus->add($documentAttendu);
$documentAttendu->setExercice($this);
}
return $this;
}
public function removeDocumentAttendu(DocumentAttendu $documentAttendu): self
{
if ($this->documentAttendus->removeElement($documentAttendu)) {
if ($documentAttendu->getExercice() === $this) {
$documentAttendu->setExercice(null);
}
}
return $this;
}

DocumentAttendu


#[ORMManyToOne(inversedBy: 'documentAttendus')]
#[ORMJoinColumn(nullable: false)]
private ?ExerciceComptable $exercice = null;
#[ORMColumn(nullable: true)]
private ?bool $recu = null;
public function getExercice(): ?ExerciceComptable
{
return $this->exercice;
}
public function setExercice(?ExerciceComptable $exercice): self
{
$this->exercice = $exercice;
return $this;
}
public function isRecu(): ?bool
{
return $this->recu;
}
public function setRecu(?bool $recu): self
{
$this->recu = $recu;
return $this;
}

What I tried

$qb = $this->createQueryBuilder( 'ec' );
$qb->join( 'ec.documentAttendus', 'da');
$qb->andWhere('da.recu = true');

这个不能正常工作。如果只有一个DocumentAttendu"有"recu"= true,则查询将找到它。我需要所有的DocumentAttendu"有"招募";=正确,而不是五分之一。

我也试过使用Criteria,但我真的不明白它是如何工作的。我试着用"having('COUNT')"之类的词……但是我不确定我用对了。

重要的是,我需要在"exercicecomptablerepository">

最简单的解决方案可能是子查询。更具体地说,使用Expr类from doctrine。使用"where不存在(子查询)",应该会给出正确的结果。

你会得到这样的东西:

// This subquery fetches all DocumentAttendu entities
// for the ExerciceComptable where recu is false 
$sub = $this->getEntityManager()->getRepository(DocumentAttendu::class)->createQueryBuilder('da');
$sub->select('da.id');
$sub->where('da.exercice = ec.id');
$sub->andWhere('da.recu IS FALSE');
// We fetch the ExerciceComptable entities, that don't
// have a result from the above sub-query
$qb = $this->createQueryBuilder('ec');
$qb->andWhere($qb->expr()-not(
$qb->expr()->exists($sub->getDQL()) // This resolves to WHERE NOT EXISTS (...)
))

简而言之:您正在获取所有没有recu = falseDocumentAttendu实体的ExerciceComptable实体

注意:如果ExerciceComptable实体没有任何documentAttendus,该查询也将返回ExerciceComptable实体

我的解决方案不是一个完整的理论解决方案,可能会使大数据的性能问题,但我相信这可能是一个很好的方法来处理非常具体的情况,如:

让我们讨论一下正确的Sql查询之前的原则,它应该是这样的:

SELECT ec.id FROM ExerciceComptable ec
INNER JOIN (SELECT COUNT(*) total, exercice_comptable_id FROM DocumentAttendu) 
all_documents ON all_documents.exercice_comptable_id = ec.id // COUNT ALL document for each execice
INNER JOIN (SELECT COUNT(*) total, exercice_comptable_id FROM DocumentAttendu da WHERE da.recu = 1) 
received_documents ON received_documents.exercice_comptable_id = ec.id // COUNT ALL received document for each execice
WHERE all_documents.total = received_document.total;

那么,只有具有total documents = received document的ExerciceComptable将被检索。
重要的是要知道select中的子查询对性能不利,因为它对每个结果做1个查询(因此,如果您有100个ExerciceComptable,它将做100个子查询),其中使用join的子查询只对整个查询做1个查询。这就是为什么我这样构建我的查询。

问题是你不会得到实体对象与一个原始mysql函数在一个存储库。所以你有两个选择。

  • 在Doctrine DQL中使用子查询(这对于非常复杂的情况是痛苦的)。我建议您只在遇到性能问题时才这样做
  • 使用raw sql -&gt执行第一个查询;只检索id ->调用原则函数findBy(['id' => $arrayOfIds])->你已经找到你要找的对象了。

这是一个诡计,这是真的。
但是我相信有原则的特定用例通常很难维护。sql查询可以很容易地测试和更改。
事实是,只有第一个查询将被维护,第二个查询将总是非常快,因为查询id非常快。

如果您想查看带有子查询的DQL示例,请参阅:Join subquery with doctrine 2 DBAL

我给了你一般的指导方针,我希望它有帮助。

永远不要忘记:永远不要在select或where中执行子查询。它的性能非常差,因为它在服务器端为每行结果执行一个子查询。使用Inner/Left Join来实现

最新更新