-->

在postPersist事件学说插入(Doctrine inserting in postPersi

2019-06-24 01:23发布

我要添加新的饲料项目上坚持实体和更新。 我写这个事件监听器(postUpdate是一样的):

public function postPersist(LifecycleEventArgs $args)
{
    $entity = $args->getEntity();
    $em = $args->getEntityManager();

    if ($entity instanceof FeedItemInterface) {
        $feed = new FeedEntity();
        $feed->setTitle($entity->getFeedTitle());
        $feed->setEntity($entity->getFeedEntityId());
        $feed->setType($entity->getFeedType());
        if($entity->isFeedTranslatable()) {
            $feed->getEnTranslation()->setTitle($entity->getFeedTitle('en'));
        }
        $em->persist($feed);
        $em->flush();
    }
}

但我得到了

完整性约束冲突:1062重复条目'30 -2' 关键‘PRIMARY’

并在日志中有两个insertations:

INSERT INTO interview_scientificdirection(interview_id,scientificdirection_id)VALUES(?,?)([30,2])INSERT INTO interview_scientificdirection(interview_id,scientificdirection_id)VALUES(?,?)([30,2])

scientificdirection是许多为我们所要坚持的实体很多关系表。 在前端应用程序的一切工作正常,但在索纳塔联系我得到了这个问题:(

Answer 1:

由于学说2.2就可以把听众的postFlush事件:

function postFlush($args) {
    $em = $args->getEntityManager();
    foreach ($em->getUnitOfWork()->getScheduledEntityInsertions() as $entity) {
        if ($entity instanceof FeedItemInterface) {
            $feed = new FeedEntity;
            ...
            $em->persist($feed);
        }
    }
    $em->flush();
}


Answer 2:

距离Francesc答案是错误的,因为在postFlush事件的变更已经是空的。 jhoffrichter的第二个答案可以工作,但矫枉过正。 走正确的做法是坚持在postPersist事件实体并在postFlush事件再次调用平齐。 但你必须要做到这一点只有当你在postPersist事件改变了一些东西,否则你创建一个无限循环。

public function postPersist(LifecycleEventArgs $args) {

    $entity = $args->getEntity();
    $em = $args->getEntityManager();

    if($entity instanceof FeedItemInterface) {
        $feed = new FeedEntity();
        $feed->setTitle($entity->getFeedTitle());
        $feed->setEntity($entity->getFeedEntityId());
        $feed->setType($entity->getFeedType());
        if($entity->isFeedTranslatable()) {
            $feed->getEnTranslation()->setTitle($entity->getFeedTitle('en'));
        }
        $em->persist($feed);
        $this->needsFlush = true;
    }
}

public function postFlush(PostFlushEventArgs $eventArgs)
{
    if ($this->needsFlush) {
        $this->needsFlush = false;
        $eventArgs->getEntityManager()->flush();
    }
}


Answer 3:

如果您需要保留的其他对象,在学说的postPersist或postUpdate处理程序,可悲的是,不恰当的地方去。 今天我同样的问题挣扎,因为我需要生成在处理一些信息的条目。

此时的问题是,postPersist处理程序的冲刷事件期间调用,而不是之后。 所以,你不能在这里坚持额外的对象,因为他们没有得到事后冲洗。 此外,您不能在postPersist处理程序中调用flush,因为这可能会导致ducplicate条目(如你所经历)。

去使用从教义onFlush处理的一种方式,记录在这里: http://doctrine-orm.readthedocs.org/en/latest/reference/events.html#onflush

如果你需要的数据库对象的插入标识,作为实体尚未被写入到该处理程序的数据库,这只是问题的。 如果你不需要这些ID,你的罚款与教义ofFlush事件。

对我来说,解决方案是一个有点不同。 我目前工作的一个Symfony2的项目,以及(在回调和更新后)需要插入数据库对象的ID。

我创建了Symfony2的一个新的服务,这基本上只是就像我的消息的队列。 在postPersist更新,我只需填写队列的条目。 我有注册其他处理kernel.response ,然后需要这些条目,并将它们持久化到数据库中。 (沿此线的东西: http://symfony.com/doc/current/cookbook/service_container/event_listener.html )

我希望我不会从话题岔开了太多在这里,但因为它是我真的很挣扎,我希望有些人可能会发现这很有用。

造成这种情况的服务项目有:

 amq_messages_chain:
   class: Acme\StoreBundle\Listener\AmqMessagesChain

 amqflush:
   class: Acme\StoreBundle\Listener\AmqFlush
   arguments: [ @doctrine.orm.entity_manager, @amq_messages_chain, @logger ]
   tags:
     - { name: kernel.event_listener, event: kernel.response, method: onResponse, priority: 5 }

 doctrine.listener:
  class: Acme\StoreBundle\Listener\AmqListener
  arguments: [ @logger, @amq_messages_chain ]
  tags:
    - { name: doctrine.event_listener, event: postPersist }
    - { name: doctrine.event_listener, event: postUpdate }
    - { name: doctrine.event_listener, event: prePersist }

你不能使用doctrine.listener这一点,因为这将导致循环依赖(因为你需要该服务的实体管理器,但实体管理器所需要的服务....)

这工作就像一个魅力。 如果您需要了解它的更多信息,请不要犹豫,问,我很高兴一些例子添加到这个。



Answer 4:

那么,如何继承人我已经在SF 2.0和2.2进行:

Listener类:

<?php
namespace YourNamespace\EventListener;

use Doctrine\ORM\Mapping\PostPersist;


/*
 * ORMListener class
 *
 * @author:        Marco Aurélio Simão
 * @description:   Listener para realizar operações em qualquer objeto manipulado pelo Doctrine 2.2
 */

use Doctrine\ORM\UnitOfWork;

use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\Common\EventArgs;
use Doctrine\ORM\Mapping\PrePersist;
use Doctrine\ORM\Event\PostFlushEventArgs;
use Doctrine\ORM\Mapping\PostUpdate;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Event\PreFlushEventArgs;
use Enova\EntitiesBundle\Entity\Entidades;

use Doctrine\ORM\Event\LifecycleEventArgs;

use Enova\EntitiesBundle\Entity\Tagged;
use Enova\EntitiesBundle\Entity\Tags;

class ORMListener
{
    protected $extra_update;

    public function __construct($container)
    {
        $this->container    = $container;
        $this->extra_update = false;
    }

    public function onFlush(OnFlushEventArgs $args)
    {
        $securityContext = $this->container->get('security.context');
        $em              = $args->getEntityManager();

        $uow             = $em->getUnitOfWork();
        $cmf             = $em->getMetadataFactory();

        foreach ($uow->getScheduledEntityInsertions() AS $entity)
        {
            $meta = $cmf->getMetadataFor(get_class($entity));

            $this->updateTagged($em, $entity);
        }

        foreach ($uow->getScheduledEntityUpdates() as $entity)
        {
            $meta = $cmf->getMetadataFor(get_class($entity));

            $this->updateTagged($em, $entity);
        }
    }

    public function updateTagged($em, $entity)
    {
      $entityTags = $entity->getTags();

      $a = array_shift($entityTags);
      //in my case, i have already sent the object from the form, but you could just replace this part for new Object() etc

      $uow      = $em->getUnitOfWork();
      $cmf      = $em->getMetadataFactory();
      $meta     = $cmf->getMetadataFor(get_class($a));

      $em->persist($a);

      $uow->computeChangeSet($meta, $a);
    }

}

Config.yml:

services:
    updated_by.listener:
        class: YourNamespace\EventListener\ORMListener
        arguments: [@service_container]
        tags:
            - { name: doctrine.event_listener, event: onFlush, method: onFlush }

希望能帮助到你 ;)



Answer 5:

从jhoffrichter该解决方案的工作非常出色。 如果您使用控制台命令你应该添加一个标签为事件command.terminate。 否则就不是控制台命令内工作。 见https://stackoverflow.com/a/19737608/1526162

config.yml

amq_messages_chain:
   class: Acme\StoreBundle\Listener\AmqMessagesChain

amqflush:
   class: Acme\StoreBundle\Listener\AmqFlush
   arguments: [ @doctrine.orm.entity_manager, @amq_messages_chain, @logger ]
   tags:
     - { name: kernel.event_listener, event: kernel.response, method: onResponse, priority: 5 }
     - { name: kernel.event_listener, event: command.terminate, method: onResponse }

doctrine.listener:
  class: Acme\StoreBundle\Listener\AmqListener
  arguments: [ @logger, @amq_messages_chain ]
  tags:
    - { name: doctrine.event_listener, event: postPersist }
    - { name: doctrine.event_listener, event: postUpdate }
    - { name: doctrine.event_listener, event: prePersist }


文章来源: Doctrine inserting in postPersist event