2016-12-31 1 views
1

Я использую doctrine2 и symfony3.1Doctrine2: получить счет от одного до многих отношений непосредственно отображенных в сущности

У меня есть список 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 излучаемого.

Проблема на стороне ОРМ, что результаты организованы как этот

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

Я хотел бы знать, как дать намеки доктрины так, чтобы nbrTickets стать собственностью Movie непосредственно, (в настоящее время я придется повторять себе), а еще делать только 1 SQL запрос (я сильно emphasi, так что я не хочу делать movie.tickets | length в моей веточке

ответ должен отвечать следующим требованиям:

  • делает 1 и только один SQL запроса (=> иначе как моя страница дисплей 100 фильмов, он будет выдавать, только для этого, 101 запросов)
  • разрешения на прямой доступ результата внутри объекта (=> в противном случае, как сказано выше, у меня уже есть решение, которое извлекает данные, которые я хочу, я заинтересован в том, чтобы сделать код больше привязанным к ORM)
  • не извлекает слишком много данных.

Ответ «в настоящее время невозможно с учением» также является приемлемым.

+1

Что не так с использованием '{{movie.tickets | length}} 'в вашем файле Twig? Это похоже на простое решение. Или, может быть, вам нужен счет в контроллере? –

+0

, потому что при этом запускается n + 1 проблема https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/, теперь для этого потребуется выполнить еще N запросов SQL для отображения N фильмов –

+0

Я вижу только одно решение здесь , Гидрат приводит к массиву. Чем вы можете пройти все, что захотите. Поэтому 'getArrayResult()' должен работать здесь вместо 'getResult()', но, конечно, вы не получаете объект. – user254319

ответ

0

В настоящее время кажется, что нет простого способа получить его непосредственно в eni ти. Вы можете сделать это только аппроксимативное решение: (что получить работу, но не так элегантно)

  • использования $movie->tickets->count(), который элегантно, но слишком дорого (вы еще 1 запрос SQL для каждого фильма)
  • с использованием addSelect (мое текущее решение), который делает 1 запрос на получение всех данных, но для этого требуется дополнительный код для сопоставления счета в вашей сущности.

Кажется, было решение в Учении 1, как описано here, как вы были в состоянии получить доступ специального атрибута $this->_values, содержащий не-сопоставляются значения внутри объекта, который не кажется, больше не быть.

1

Вам нужны соответствующие аннотации для отношения к работе в объекте Movie и Ticket.

Movie объект: объект

* 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(); 
} 

Вам нужно создать getTickets функции для объекта Movie следующим образом:

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

Тогда вы извлекаете фильмы следующего вызова репозитария:

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

и, наконец, вы получите билеты:

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

и посчитать их:

$tickets->count() 
+0

К сожалению, это уже то, что у меня есть (я должен был его уточнить). Это выдаст один видеоролик с запросом на подсчет голосов, поэтому, если я покажу 100 лучших из лучших продаваемых фильмов, теперь запрос на страницу 101. –

+0

Я обновил свой вопрос, чтобы яснее, что я ищу. –