Doctrine2:PreFlush挂钩会超时

时间:2019-01-17 14:16:32

标签: doctrine-orm symfony4 timeoutexception

我有两个实体。

首先是我的父实体,它具有称为productsCount的属性。 这个实体有另一个与之链接的实体,称为商店,商店已链接到房间。每个房间可以有多种产品。

当我编辑分配给房间的产品时,我想更新父产品计数以存储所有商店中所有房间中所有产品的计数。

我有一个确实计算计数的SQL查询。每次我用新产品更新会议室时,都需要这样做。这是通过使用Room实体上的EntityListener的preFlush挂钩完成的。

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 :(得分:1)

所以,经过几个小时的战斗,我终于找到了解决方案。

原来,我不必坚持,也不必刷新更改。解决方案是使用工作单元重新计算$ parent上的更改,然后主义将自行清除它们。我还必须更改对产品进行计数的方式,因为在preFlush阶段,更改尚未在数据库中进行,因此查询将无法正常工作。这就是为什么我要遍历关系树来手动计算它们的原因。

这是一个代码示例。

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

答案 1 :(得分:0)

原因是递归:您正在从订户调用androidx,EntityManager输入$em->flush();,触发flush事件,该事件调用您的处理程序,然后再次调用preFlush,依此类推上。

在更改集计算之前会调用IIRC preFlush,因此仅用新值更新实体就足以使Doctrine检测到该更改。