简体   繁体   English

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

[英]Doctrine2: get count of one to many relation directly mapped in entity

I'm using doctrine2 and symfony3.1 我正在使用doctrine2和symfony3.1

I have a list of Movie for which people can buy Ticket , using a one to many relationship 我有一个Movie列表,人们可以使用一对多关系购买Movie Ticket

On the dashboard I would like to display the list of movies, with the number of tickets bought for each 我要在仪表板上显示电影列表,以及每张电影的购票数量

I get the data I want by doing this 通过这样做我得到了我想要的数据

    $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()
    ;

it produces for 100 movies, 1 requests: 它可以制作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;

which is perfectly what I want in term of SQL request emitted. 就发出的SQL请求而言,这正是我想要的。

The problem is on the ORM side, that the results is organized like this 问题是在ORM方面,结果是这样组织的

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

I would like to know how to give hints to Doctrine so that nbrTickets become a property of Movie directly, (currently I have to iterate myself) while still doing only 1 SQL query (I strongly emphasi so I don't want to do movie.tickets | length in my twig 我想知道如何给Doctrine提示,以便nbrTickets直接成为Movie的属性,(目前我必须迭代自己),同时仍然只执行1个SQL查询 (我非常强调,所以我不想做movie.tickets | length我的树枝movie.tickets | length

The answer should meet the following requirements: 答案应满足以下要求:

  • doing 1 and only one SQL query ( => otherwise as my page display 100 movies, it will issue, only for this, 101 queries) 执行1个 SQL查询(=>否则,因为我的页面显示100部电影,仅此会发出101条查询)
  • permit to directly access the result from within the entity ( => otherwise as said above, I already have a solution that retrieve the data I want, I'm interested on making the code to stick more to the ORM) 允许直接从实体内部访问结果(=>否则如上所述,我已经有一个解决方案,可以检索想要的数据,我有兴趣让代码更加遵守ORM)
  • not retrieve too much data. 不会检索太多数据。

The answer "it's currently not possible with doctrine" is also acceptable. 答案“目前尚无法用学说”也可以接受。

You need proper annotations for the relation to work in Movie and Ticket entity. 您需要适当的注释才能在电影和票证实体中使用该关系。

Movie entity: 电影实体:

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

Ticket entity: 票证实体:

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

For the relation you need to define an array collection in the constructor 对于关系,您需要在构造函数中定义一个数组集合

public function __construct() {
    $this->tickets = new ArrayCollection();
}

You need to create a getTickets function for the Movie entity like that: 您需要像这样为Movie实体创建getTickets函数:

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

Then you retrieve the movies with the following repository call: 然后,通过以下存储库调用检索电影:

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

and finally you retrieve the tickets: 最后,您检索票证:

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

and you count them with: 然后用以下方式计算它们:

    $tickets->count()

Currently it seems there's no simple way to get it mapped directly in the entity. 当前,似乎没有简单的方法可以直接将其映射到实体中。 You can only do approximative solution: (which get the job done but not as elegantly) 您只能做一个近似的解决方案:(这可以完成工作,但不能那么优雅)

  • using $movie->tickets->count() which is elegant but too costly (you do 1 more sql request for each movie) 使用$movie->tickets->count()这很优雅,但成本太高(每部电影您还要执行1个sql请求)
  • using a addSelect (my current solution) which does 1 request to get all the data, but which need additional code to map the count in your entity. 使用addSelect (我当前的解决方案)执行一次请求以获取所有数据,但需要其他代码来映射您实体中的计数。

It seems there was a solution in Doctrine 1 as explained here as you were able to access a special attribute $this->_values containing the non-mapped value from within the entity which seems to no more be the case. 似乎在教义1中有一种解决方案,如此处所述因为您能够从实体内部访问包含非映射值的特殊属性$this->_values ,情况似乎不再如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM