Doctrine2: хук PreFlush делает тайм-аут - PullRequest
0 голосов
/ 17 января 2019

У меня есть две сущности.

Во-первых, это мой родительский объект, свойство которого называется productsCount. У этого объекта есть еще один объект, связанный с ним, который называется «Магазин» и «Магазин, связанный с комнатой». В каждой комнате может быть несколько товаров.

Когда я редактирую продукты, назначенные для комнаты, я хочу обновить Parent productsCount для хранения количества всех продуктов во всех комнатах во всех магазинах.

У меня есть SQL-запрос, который вычисляет количество. Мне нужно делать это каждый раз, когда я обновляю Комнату новыми продуктами. Это делается с помощью ловушки preFlush с использованием EntityListener на объекте Room.

Хук preFlush срабатывает должным образом, но по какой-то причине время ожидания истекает.

Вот пример кода preFlush

    public function preFlush(Room $room, PreFlushEventArgs $args)
  {
    $em = $args->getEntityManager();
    $parent = $room->getStore()->getParent();
    $rsm = new ResultSetMapping();
    $rsm->addScalarResult('COUNT(product_id)', 'count');

    $query = $em->createNativeQuery(
      'select COUNT(product_id)
            from room_product where `room_id` in
            (select id from room where store_id in
            (select id from store where parent_id = :parentId))', $rsm);
    $query->setParameter('parentId', $parent->getId());
    $result = $query->getOneOrNullResult();
    $parent->setNumberOfServices($result['count']);
    $em->persist($parent);
    $em->flush();
  }

Запрос должен работать нормально, поэтому я думаю, что он как-то связан с очисткой и сохранением родительской сущности.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 18 января 2019

Итак, я смог найти решение после нескольких часов борьбы.

Оказывается, мне не нужно ни настаивать, ни сбрасывать изменения.Решение состоит в том, чтобы использовать Unit of Work для пересчета изменений в $ parent, а затем доктрина сбросит их самостоятельно.Мне также пришлось изменить способ подсчета продуктов, так как на этапе предварительной проверки изменения еще нет в базе данных, поэтому запрос не будет работать должным образом.Вот почему я считаю их вручную, обходя дерево отношений.

Вот пример кода.

public function preFlush(Room $room, PreFlushEventArgs $args)
  {
    $em = $args->getEntityManager();
    $numOfProducts = 0;
    $parent = $room->getStore()->getParent();
    foreach($parent->getStores() as $store) {
      foreach($store->getRooms() as $room) {
        $numOfServices += count($room->getProducts());
      }
    }
    $parent->setNumberOfProducts($numOfProducts);
    $classMetadata = $em->getClassMetadata(get_class($parent));
    $em->getUnitOfWork()->computeChangeSet($classMetadata, $parent);
  }
0 голосов
/ 17 января 2019

Причина в рекурсии: вы звоните $em->flush(); от абонента, EntityManager вводит flush, запускает событие preFlush, которое вызывает ваш обработчик, который снова вызывает $em->flush() и т. Д.

IIRC preFlush вызывается перед вычислением набора изменений, так что простого обновления вашей сущности новым значением должно быть достаточно, чтобы Doctrine обнаружила указанное изменение.

...