简体   繁体   中英

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

I'm using doctrine2 and symfony3.1

I have a list of Movie for which people can buy Ticket , using a one to many relationship

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:

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.

The problem is on the ORM side, that the results is organized like this

[
   [ 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

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)
  • 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)
  • 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:

 * 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)
  • 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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