如何检查是否实体学说2改变了吗?(How to check if entity changed in

2019-06-24 22:49发布

我需要检查是否持久实体已发生变化,需要对数据库进行更新。 我做了什么(而没有工作)是以下几点:

$product = $entityManager->getRepository('Product')->find(3);
$product->setName('A different name');

var_export($entityManager->getUnitOfWork()->isScheduledForUpdate($product));

该代码打印总是false ,我也尝试刷新前检查工作的单位,但没有奏效。

任何人有什么建议?

Answer 1:

我会检查你的setName功能实际上是做一些事情($这个- >名称= $名字......),如果它已经工作的第一件事情,那么你可以定义你的services.yml事件监听器被触发时你叫齐平。

entity.listener:
  class: YourName\YourBundle\EventListener\EntityListener
  calls:
    - [setContainer,  ["@service_container"]]
  tags:
    - { name: doctrine.event_listener, event: onFlush }

然后,你定义EntityListener

namespace YourName\YourBundle\EventListener;

use Doctrine\ORM\Event;
use Symfony\Component\DependencyInjection\ContainerAware;

class EntityListener extends ContainerAware
{   

    /**
     * Gets all the entities to flush
     *
     * @param Event\OnFlushEventArgs $eventArgs Event args
     */
    public function onFlush(Event\OnFlushEventArgs $eventArgs)
    {   
        $em = $eventArgs->getEntityManager();
        $uow = $em->getUnitOfWork();

        //Insertions
        foreach ($uow->getScheduledEntityInsertions() as $entity) {
            # your code here for the inserted entities
        }

        //Updates
        foreach ($uow->getScheduledEntityUpdates() as $entity) {
            # your code here for the updated entities
        }

        //Deletions
        foreach ($uow->getScheduledEntityDeletions() as $entity) {
            # your code here for the deleted entities
        }
    }
}

如果您需要了解哪些实体被改变,但与他们做的东西 ,他们一直保存到数据库中,只存储实体的私人阵列改变,一个则定义了从阵列中获取实体onFlush事件。

BTW,触发这种需要添加对实体@ORM \ HasLifecycleCallbacks事件。



Answer 2:

我并不需要/想我的情况下创建侦听器,这样我结束了

$product->setName('A different name');
$uow = $entityManager->getUnitOfWork();
$uow->computeChangeSets();
if ($uow->isEntityScheduled($product)) {
    // My entity has changed
}


Answer 3:

你也可能想看看更新前的情况下,如果你需要与他们的新旧值进入实体领域。

一个例子的位大多是从所提供的链接采取:

<?php
class NeverAliceOnlyBobListener
{
    public function preUpdate(PreUpdateEventArgs $eventArgs)
    {
        if ($eventArgs->getEntity() instanceof User) {
            if ($eventArgs->hasChangedField('name') && $eventArgs->getNewValue('name') == 'Alice') {
                $oldValue = $eventArgs->getOldValue('name');
                $eventArgs->setNewValue('name', 'Bob');
            }
        }
    }
}


Answer 4:

Doctrine2文档。 17.更改跟踪策略

(17.3通知)如果使用第三种形式为我做的,你可以,如果你的实体变为做测试:

$uow = $entityManager->getUnitOfWork();
$uow->computeChangeSets();
$aChangeSet = $uow->getEntityChangeSet($oEntity);

如果什么都没有改变,它将返回空数组。



Answer 5:

这个问题是很老,但有可能还是有些组可能从一个不同的角度面对这个问题的人。 该UnitOfWork的伟大工程,但它只返回变化的阵列。 它可以是一个痛苦的对接,当有人实际上并不知道哪些领域可能已经改变,只是希望得到整个实体作为一个对象来比较$oldEntity$newEntity 。 即使该事件的名称是更新前如果有人将尝试如下,从数据库中读取数据:

$er->find($id);

返回的实体将包含所有的变化。 解决方法是很简单,但它也有一些挂钩:

public function preUpdate(Entity $entity, PreUpdateEventArgs $args)
{
    $entity = clone $entity; //as Doctrine under the hood 
                             //uses reference to manage entities you might want 
                             //to work on the entity copy. Otherwise,        
                             //the below refresh($entity) will affect both 
                             //old and new entity.
    $em = $args->getEntityManager();
    $currentEntity = $em->getRepository('AppBundle:Entity')->find($entity->getId());
    $em->refresh($currentEntity);

}

对于那些谁正在使用其他事件,如前置液,我赶紧检查,并因为可能的解决方法没有工作refresh()方法再次放弃任何冲洗需求的变化等什么做的是调用刷新监听器,并创建一些静态的$alreadyFlushed切换,以避免循环引用。



Answer 6:

我好奇的原则,每个人都记录postFlush,在某些情况下,你有一个正在进行中的事务。 我想指出,也有postTransactionCommit,这可能取决于你想在postFlush事件达到什么是安全的。



Answer 7:

根据我的需求,这里的答案, 该文档 ,我想出了一个下述溶液modifiedAt在实体时间戳。

/**
 * @Doctrine\ORM\Mapping\PreUpdate()
 *
 * @param \Doctrine\ORM\Event\PreUpdateEventArgs $args
 * @return $this
 */
public function preUpdateModifiedAt(\Doctrine\ORM\Event\PreUpdateEventArgs $args)
{
    $this->setModifiedAt(new \DateTime('now'));

    return $this;
}

这是基于什么样的文档说这个Event ,而不是其他可用的,如PostPersistPreFlush

更新前的是最严格的使用事件,因为它被称为更新语句被调用了EntityManager#flush()方法中的实体权利之前。 请注意,当计算变更为空,则不会触发此事件。

使用PreUpdate ,而不是别人让您将所有的计算和计算密集的功能已经被定义学说的过程。 手动触发的变更,比如在计算这些 答案以上是服务器CPU密集型。 该onFlush事件,如在使用公认的答案是选项(在演示的方式),但如果你依赖于检测更改了实体,你可以与上面的函数( preUpdateModifiedAt(PreUpdateEventArgs $args) )。



Answer 8:

我同意@Andrew阿特金森时,他说:

你也可能想看看更新前的情况下,如果你需要与他们的新旧值进入实体领域。

但我不同意他提出的例子,从我的经验,有一种更好的方法来检查,如果事情发生了转变与否。

<?php
class Spock
{
    public function preUpdate(PreUpdateEventArgs $eventArgs)
    {
        if (!empty($eventArgs->getEntityChangeSet())) {
            // fill this how you see fit
        }
    }
}

这样,如果真的是有一些领域,改变与否,如果只被触发。

至于如果这个或那个领域进行改怎么做,那么是的,我推荐他的解决方案。



文章来源: How to check if entity changed in Doctrine 2?