我有一个OneToMany
关系,其中一个足球队有很多球员。我想列出所有足球队并显示每队的队长名称。
每个玩家实体都有一个外键(team_id)和一个字段'captain',设置为0或1.我正在运行以下查询:
$teams = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()->getResult();
然后当我循环遍历每个团队时,我运行team.getTeamCaptain()。getName()这是我的团队实体中的过滤器:
public function getTeamCaptain() {
$them = $this->players->filter(function($p) {
return $p->getCaptain() == 1;
});
return $them->first();
}
有更好的方法来运行此查询吗?
答案 0 :(得分:4)
首先,您可能希望fetch-join每个检索到的团队的玩家避免在渲染模板期间延迟加载它们。这是DQL:
SELECT
t, p
FROM
FootballWebsiteBundle:Team t
LEFT JOIN
t.players p
WHERE
t.deleted = 0
ORDER BY
t.name DESC
可以使用以下查询构建器API调用构建:
$teamsQuery = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->addSelect('p')
->leftJoin('t.players', 'p')
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()
然后将此查询包装到Paginator
对象中(从setMaxResults
和setFirstResult
cannot be trusted when fetch-joining开始):
$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($teamsQuery, true);
$teamsQuery
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
在您的视图中,您可以像遵循伪代码一样迭代团队:
foreach ($paginator as $team) {
echo $team->getTeamCaptain() . "\n";
}
您还可以使用Selectable
API在getTeamCaptain
方法中获得额外的性能:
public function getTeamCaptain() {
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->andWhere($criteria->expr()->eq('captain', 1));
return $this->players->matching($criteria)->first();
}
此处的优势主要与关联players
尚未初始化时相关,因为这样可以避免完全加载它。情况并非如此,但我认为这是一个很好的做法(而不是重新发明集合过滤逻辑)。