Doctrine2:获取直接映射到实体中的一对多关系的计数

时间:2016-12-31 16:45:00

标签: php doctrine-orm symfony

我使用的是doctrine2和symfony3.1

我有一个Movie的列表,人们可以使用一对多的关系购买Ticket

在仪表板上,我想显示电影列表,其中包含为每个购买的门票数量

我通过这样做得到了我想要的数据

    $manager = $this->getDoctrine()->getManager();
    $builder = $manager->createQueryBuilder();

    $results = $builder
        ->select('m')
        ->from('AppBundle:Movie', 'm')
        ->addSelect($builder->expr()->count('t'))
        ->leftJoin('m.tickets', 't')
        ->groupBy('m.id')
        ->getQuery()
        ->getResult()
    ;

它可以制作100部电影,1个请求:

SELECT
       e0_.title AS title_0,
       e0_.is_published AS is_published_1,
       e0_.description AS description_2,
       e0_.author AS author_3,
       e0_.director AS director_4,
       e0_.artist_list AS artist_list_5,
       e0_.tags_list AS tags_list_6,
       e0_.creation_time AS creation_time_7,
       e0_.id AS id_8,
       COUNT(t1_.id) AS sclr_9,
       e0_.place_id AS place_id_10,
       e0_.organization_id AS organization_id_11,
       e0_.inner_image1_id AS inner_image1_id_12,
       e0_.inner_image2_id AS inner_image2_id_13,
       e0_.inner_image3_id AS inner_image3_id_14,
       e0_.image_id AS image_id_15
FROM event e0_
LEFT JOIN event_occurence e2_ ON e0_.id = e2_.event_id
LEFT JOIN ticket t1_ ON e2_.id = t1_.occurence_id
WHERE e0_.organization_id = '956744cb-6f76-4328-8ea5-c9715d762509'
GROUP BY e0_.id
LIMIT 100;

这完全是我想要发出的SQL请求。

问题在于ORM方面,结果是这样组织的

[
   [ movie, nbrTickets],
   [ movie, nbrTickets],
   [ movie, nbrTickets],
]

我想知道如何给Doctrine提示,以便nbrTickets直接成为Movie的属性,(目前我必须自己迭代),同时仍然只做 1 SQL查询(我非常强调所以我不想在我的树枝上做movie.tickets | length

答案应符合以下要求:

  • 执行 1且只有一次 SQL查询(=>否则当我的页面显示100部电影时,它会发出,仅针对此,101次查询)
  • 允许直接从实体内部访问结果(=>否则如上所述,我已经有了一个解决方案来检索我想要的数据,我对使代码更多地关注ORM感兴趣)
  • 没有检索太多数据。

答案"它目前不可能与学说#34;也是可以接受的。

2 个答案:

答案 0 :(得分:1)

您需要正确注释关系才能在Movie和Ticket实体中工作。

电影实体:

 * One user has Many tickets.
 * @ORM\OneToMany(targetEntity="Ticket", mappedBy="user")
 */
private $tickets;

票务实体:

 * Many tickets have One movie.
 * @ORM\ManyToOne(targetEntity="movie", inversedBy="tickets")
 * @ORM\JoinColumn(name="movie_id", referencedColumnName="id")
 */
private $movie;

对于您需要在构造函数

中定义数组集合的关系
public function __construct() {
    $this->tickets = new ArrayCollection();
}

您需要为Movie实体创建一个getTickets函数:

 * tickets
 *
 * @return arrayCollection
 */
public function getTickets()
{
    return $this->tickets;
}

然后使用以下存储库调用检索影片:

    $movies = $this->getDoctrine()
        ->getRepository('AppBundle:movies')
        ->findAll();

最后检索门票:

    $tickets = $movies[0]->getTickets()

你用它们计算:

    $tickets->count()

答案 1 :(得分:1)

目前似乎没有简单的方法可以直接在实体中映射它。你只能做近似解决方案:(完成工作但不优雅)

  • 使用$movie->tickets->count()优雅但成本太高(你为每部电影再做1次sql请求)
  • 使用addSelect(我当前的解决方案)执行1请求获取所有数据,但需要其他代码来映射实体中的计数。

似乎在Doctrine 1中有一个解决方案this PR,因为您可以访问一个特殊属性$this->_values,其中包含实体内部的非映射值,似乎不再是情况下。