原则 2:查询多对多关联的有效方法
Doctrine 2: Efficient way to query a many-to-many association
我在两个 table 之间建立了多对多关联(特许经营权和球员),建立了一个额外的 table (franchise_players)。
我已经创建了三个实体:
class Franchise
{
...
/**
*
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="NBA\Entity\FranchisePlayer", mappedBy="franchise")
*/
private $franchiseplayers;
...
}
class Player
{
/* some fields */
}
class FranchisePlayers
{
...
/**
* @var \NBA\Entity\Player
*
* @ORM\ManyToOne(targetEntity="NBA\Entity\Player")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="playerId", referencedColumnName="id")
* })
*/
private $player;
/**
* @var \NBA\Entity\Franchise
*
* @ORM\ManyToOne(targetEntity="NBA\Entity\Franchise")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="franchiseId", referencedColumnName="id")
* })
*/
private $franchise;
}
我的目标是获得所有相关球员的特许经营权。
显而易见的解决方案很简单但效率不高:
Get all franchises
foreach $franchise
$franchise->getFranchisePlayers()
foreach $franquisePlayer
$franquisePlayer->getPlayer()->getFullName();
另一种解决方案是获取所有特许经营权,然后执行左连接以获得每个特许经营权的相关球员:
Get all franchises
foreach $franchise
public function getCurrentPlayers(Franchise $franchise) {
$qb = $this->entityManager->createQueryBuilder();
$qb->select(array('p'))
->from('NBA\Entity\Player', 'p')
->leftjoin('NBA\Entity\FranchisePlayer','f','WITH','f.player=p')
->where('f.franchise = ?1')
->orderBy('p.surname','ASC')
->setParameter(1,$franchise);
$query = $qb->getQuery();
return $query->getResult();
}
这样我们就减少了查询的次数。
我的问题是我是否可以通过这样的一个查询来实现我的目标:
public function getFranchisesWithPlayers() {
$qb = $this->entityManager->createQueryBuilder();
$qb->select(array('f'))
->from('NBA\Entity\Franchise', 'f')
->leftJoin('NBA\Entity\FranchisePlayer','fp','WITH','fp.franchise=f')
->leftJoin('NBA\Entity\Player','p','WITH','fp.player=p')
->orderBy('f.name')
->addOrderBy('p.surname');
$query = $qb->getQuery();
return $query->getResult();
}
我认为 Franchise 实体的 franchisePlayers 字段(以及每个 FranchisePlayer 的 de Player 实体)会自动加载,但似乎并非如此。
可以吗?也许我在我的实体映射中做错了什么?
谢谢!
编辑: 昨天我确定查询越少效率越高,但现在我怀疑。也许对这个复杂查询的结果进行水合的成本大于对选项 2 的查询的每个结果进行水合的成本(在不同的查询中查询每个特许经营权的球员)。你怎么看?
文档展示了如何创建查询。可能值得一看。类似于:
$qb->select('franchise,franchisePlayer,player')
->from('NBA\Entity\Franchise', 'franchise')
->leftJoin('franchise.franchisePlayers','franchisePlayer')
->leftJoin('franchisePlayer.player','player')
->orderBy('franchise.name')
->addOrderBy('player.surname');
我在两个 table 之间建立了多对多关联(特许经营权和球员),建立了一个额外的 table (franchise_players)。 我已经创建了三个实体:
class Franchise
{
...
/**
*
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="NBA\Entity\FranchisePlayer", mappedBy="franchise")
*/
private $franchiseplayers;
...
}
class Player
{
/* some fields */
}
class FranchisePlayers
{
...
/**
* @var \NBA\Entity\Player
*
* @ORM\ManyToOne(targetEntity="NBA\Entity\Player")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="playerId", referencedColumnName="id")
* })
*/
private $player;
/**
* @var \NBA\Entity\Franchise
*
* @ORM\ManyToOne(targetEntity="NBA\Entity\Franchise")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="franchiseId", referencedColumnName="id")
* })
*/
private $franchise;
}
我的目标是获得所有相关球员的特许经营权。
显而易见的解决方案很简单但效率不高:
Get all franchises
foreach $franchise
$franchise->getFranchisePlayers()
foreach $franquisePlayer
$franquisePlayer->getPlayer()->getFullName();
另一种解决方案是获取所有特许经营权,然后执行左连接以获得每个特许经营权的相关球员:
Get all franchises
foreach $franchise
public function getCurrentPlayers(Franchise $franchise) {
$qb = $this->entityManager->createQueryBuilder();
$qb->select(array('p'))
->from('NBA\Entity\Player', 'p')
->leftjoin('NBA\Entity\FranchisePlayer','f','WITH','f.player=p')
->where('f.franchise = ?1')
->orderBy('p.surname','ASC')
->setParameter(1,$franchise);
$query = $qb->getQuery();
return $query->getResult();
}
这样我们就减少了查询的次数。
我的问题是我是否可以通过这样的一个查询来实现我的目标:
public function getFranchisesWithPlayers() {
$qb = $this->entityManager->createQueryBuilder();
$qb->select(array('f'))
->from('NBA\Entity\Franchise', 'f')
->leftJoin('NBA\Entity\FranchisePlayer','fp','WITH','fp.franchise=f')
->leftJoin('NBA\Entity\Player','p','WITH','fp.player=p')
->orderBy('f.name')
->addOrderBy('p.surname');
$query = $qb->getQuery();
return $query->getResult();
}
我认为 Franchise 实体的 franchisePlayers 字段(以及每个 FranchisePlayer 的 de Player 实体)会自动加载,但似乎并非如此。
可以吗?也许我在我的实体映射中做错了什么?
谢谢!
编辑: 昨天我确定查询越少效率越高,但现在我怀疑。也许对这个复杂查询的结果进行水合的成本大于对选项 2 的查询的每个结果进行水合的成本(在不同的查询中查询每个特许经营权的球员)。你怎么看?
文档展示了如何创建查询。可能值得一看。类似于:
$qb->select('franchise,franchisePlayer,player')
->from('NBA\Entity\Franchise', 'franchise')
->leftJoin('franchise.franchisePlayers','franchisePlayer')
->leftJoin('franchisePlayer.player','player')
->orderBy('franchise.name')
->addOrderBy('player.surname');