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

vltsax25  于 2023-01-21  发布在  其他
关注(0)|答案(2)|浏览(136)

在我的Symfony项目中,我有一个“ExerciceComptable”和一个“DocumentAttendu”实体。在ExerciceComptable中有一个引用DocumentAttendu(OneToMany)的关系。在DocumentAttendu中,我有一个名为“recu”的属性,它是一个布尔值。
我需要检索所有已完成的“ExerciceComptable”,这意味着“ExerciceComptable”的所有“DocumentAttendu”都将属性“recu”设置为true。
我怎样才能做到呢?

可执行

#[ORM\OneToMany(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;
}

文件出席人

#[ORM\ManyToOne(inversedBy: 'documentAttendus')]
#[ORM\JoinColumn(nullable: false)]
private ?ExerciceComptable $exercice = null;

#[ORM\Column(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;
}

"我所尝试的"

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

如果只有一个“DocumentAttendu”具有“recu”= true,则查询将找到它。我需要所有“DocumentAttendu”具有“recu”= true,而不是仅五个中的一个。
我也尝试过使用Criteria,但我不太明白它是怎么工作的。我尝试过一些行,比如“having('COUNT ')"等等...但我不确定我是否正确地使用了它。
重要的一点,我需要在“ExerciceComptableRepository”中。

omtl5h9j

omtl5h9j1#

最简单的解决方案可能是子查询。更具体地说,使用来自doctrine的Expr类。使用“where not exists (subquery)“,应该会给予出正确的结果。
你会得到这样的结果:

// 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 (...)
))

简而言之:您将获取所有不具有DocumentAttendu实体的ExerciceComptable实体,其中recu = false

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

mrfwxfqh

mrfwxfqh2#

我的解决方案不是一个完整的理论解决方案,可能会导致更大数据的性能问题,但我相信它可能是处理此类非常具体的情况的一个很好的方法。
让我们来谈谈正确的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;

则仅检索文档总数=已接收文档的ExerciceComptable
需要注意的是select内部的子查询对性能不好,因为它对每个结果只执行一个查询(所以如果你有100个ExerciceComptable,它将执行100个子查询),而使用join的子查询对整个查询只执行一个查询。
问题是你不会在仓库中得到带有原始mysql函数的实体对象,所以你有两个选择。

  • 在DoctrineDQL内部使用子查询(对于非常复杂的情况来说是痛苦的)。我建议您只有在遇到性能问题时才这样做
  • 用原始sql执行第一个查询-〉只检索id-〉调用doctrine函数findBy(['id' => $arrayOfIds])-〉您得到了要查找的对象。

这是个骗局,是真的。
但我相信特定的用例和教条往往很难维护。其中sql查询可以很容易地测试和更改。
事实上,只有第一个查询需要维护,第二个查询总是非常快,因为对id的查询非常快。
如果您想查看DQL与子查询的案例,请查看:Join subquery with doctrine 2 DBAL
我给了你一般性的指导方针,我希望它能有所帮助。

**永远不要忘记:**永远不要在select或where中执行子查询。它的性能非常差,因为它在服务器端为每一行结果执行一个子查询。请使用内/左连接来执行此操作

相关问题