问题
I've been struggling with an annoying issue for a while. I'm trying to create Notification entities associated to InventoryItems that expire.
These InventoryItems are generated automatically for users, but users can edit them and set expiry date on them individually. Upon saving, if an InventoryItem has an expiry date, a Notification entity is generated and associated to it. So these Notification entities are created when an entity is updated and hence onPersist event is not going to work.
Everything seems to work fine and Notifications are generated upon saving InventoryItems as expected. Only problem is, when a Notification is created for the first time, even though it's saved properly, changes to the InventoryItem are not saved. That is a Notification with correct expiry date is created, but the expiry date is not saved on the InventoryItem.
Here's my onFlush code:
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityUpdates() as $entity) {
if ($entity instanceof NotificableInterface) {
if ($entity->generatesNotification()){
$notification = $this->notificationManager->generateNotificationForEntity($entity) ;
if ( $notification ) {
$uow->persist($notification) ;
}
$entity->setNotification($notification) ;
$uow->persist($entity);
$uow->computeChangeSets();
}
}
}
}
The problem only occurs the first time a Notification is associated to an entity, i.e. the first time an expiry date is set on an InventoryItem. In later instances when expiry date is updated, the update is reflected correctly on both the Notification and InventoryItem.
Any ideas or suggestions would be appreciated.
Thanks
回答1:
You need to call computeChangeset specifically on your newly created or updated entity. Just calling computeChangeSets is not enough.
$metaData = $em->getClassMetadata('Your\NameSpace\Entity\YourNotificationEntity');
$uow->computeChangeSet($metaData, $notification);
回答2:
Thanks Richard. You pointed me to the right direction. I needed to recompute the change set on the parent entity (InventoryItem) to get things working properly. Additionally I had to call computeChangeSets on the unit of work to get rid of the invalid parameter number error (such as the one explained symfony2 + doctrine: modify a child entity on `onFlush`: "Invalid parameter number: number of bound variables does not match number of tokens")
Note I ended up also removing:
if ( $notification ) {
$uow->persist($notification) ;
}
Which never made sense, since I had set cascade persist on the association in my entity and should have cascaded down automatically.
My final solution is:
public function onFlush(OnFlushEventArgs $args)
{
$em = $args->getEntityManager();
$uow = $em->getUnitOfWork();
foreach ($uow->getScheduledEntityUpdates() as $entity) {
if ($entity instanceof NotificableInterface) {
if ($entity->generatesNotification()){
$notification = $this->notificationManager->generateNotificationForEntity($entity) ;
$entity->setNotification($notification) ;
// if ( $notification ) {
// $uow->persist($notification) ;
// }
$metaData = $em->getClassMetadata(get_class($entity));
$uow->recomputeSingleEntityChangeSet($metaData, $entity);
$uow->computeChangeSets();
}
}
}
}
来源:https://stackoverflow.com/questions/34342324/doctrine-eventlistener-onflush-does-not-save-original-entity