34

永続化されたエンティティが変更され、データベースで更新する必要があるかどうかを確認する必要があります。私が作成した(そして機能しなかった)のは次のとおりです。

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

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

そのコードは常に出力falseされます。作業単位を確認する前にフラッシュも試みましたが、機能しませんでした。

誰にも提案がありますか?

4

9 に答える 9

28

setName関数が実際に何かを実行していることを最初に確認します($this-> name = $name...) 既に機能している場合は、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 イベントを定義します。

ところで、この種のイベントをトリガーするには、エンティティに @ORM\HasLifecycleCallbacks を追加する必要があります。

于 2012-05-29T13:48:13.277 に答える
2

この問題はかなり古いものですが、別の観点からこの問題に直面している人々がまだいる可能性があります。UnitOfWorkうまく機能しますが、変更の配列のみを返します。どのフィールドが変更された可能性があるのか​​ を実際に知らず、エンティティ全体をオブジェクトとして取得して比較したいだけの場合、それは面倒なことになる可能性があり$oldEntityます$newEntity. イベントの名前は preUpdate ですが、誰かが次のようにデータベースからデータを取得しようとする場合:

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

}

preFlush のような別のイベントを使用している人のために、私はすぐにそれを確認しましたが、おそらくメソッドがフラッシュの変更を破棄するため、回避策はうまく機能しませんでした。そのrefresh()ため、リスナーでもう一度フラッシュを呼び出して作成する必要があります循環参照を避けるための静的$alreadyFlushedトグル。

于 2017-01-10T10:09:45.397 に答える
0

@Andrew Atkinsonが言ったとき、私は同意します:

古い値と新しい値を持つエンティティ フィールドにアクセスする必要がある場合は、PreUpdateイベントも確認することをお勧めします。

しかし、彼が提案した例には同意しません。私の経験から、何かが変わったかどうかを確認するより良い方法があります。

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

このように、実際に変更されたフィールドがあるかどうかにかかわらず、if はトリガーされます。

このフィールドまたはそのフィールドが変更された場合の方法については、ええ、彼の解決策をお勧めします。

于 2018-08-06T07:01:56.427 に答える