我正在开发一个基于Symfony 2.8的项目,该项目基本上是一个在线地址簿。
EntityDeletionListener
用于处理postRemove
事件,以便将某些信息添加到删除日志中,这是一些内部簿记所需的:
class EntityDeletionListener implements EventSubscriber {
public function getSubscribedEvents() {
return array('postRemove');
}
public function postRemove(LifecycleEventArgs $args) {
$entity = $args->getEntity();
if (!$entity->shouldAddToDeleteLog())
return ;
$em = $args->getEntityManager();
$repo = $em->getRepository('AppBundle:DeleteLog');
$log = $repo->createEntity();
$log->setGuid($entity->getGuid());
...
$em->persist($log);
// Flush entity manager if not disabled in entity settings
if ($entity->shouldFlushDeleteLog())
$em->flush();
}
}
这没有任何问题:每次删除Contact
实体时,都会自动创建删除日志条目。
现在我正在开发一个批量删除任意数量的选定Contacts
的选项。
为了加快处理速度,实体管理器不会在每次删除操作后刷新,而是仅在处理完一些批处理后才刷新。
class ContactRepository extends EntityRepository {
public function bulkDelete($guids) {
$this->_em->getConnection()->beginTransaction();
try {
$batchSize = 100;
$currentBatch = 0;
foreach ($guids as $guid) {
$contact = $this->findOneByGuid($guid);
if ($contact) {
// DO NOT FLUSH EVERY DELETE LOG
$contact->setDeleteLogFlush(false);
$this->_em->remove($contact);
$currentBatch++;
if ($currentBatch % $batchSize === 0)
$this->_em->flush();
}
}
$this->_em->flush();
$this->_em->getConnection()->commit();
} catch (\Exception $ex) {
$this->_em->getConnection()->rollBack();
return false;
}
}
}
问题1:
如果我使用$contact->setDeleteLogFlush(false)
来避免自动刷新每个DeleteLog,则DeleteLogs
根本不会保留。此外,Contact
实体被正确删除,并且每次删除操作都会执行postRemove
,日志不会持久保存到数据库。
没有异常或其他错误可以解释为什么日志不会持久化。即使存在错误,在这种情况下,完整的事务也会失败,并且Contacts
也不会被删除。但它们被删除了......
问题2:
如果不使用$contact->setDeleteLogFlush(false)
postRemove
侦听器刷新每个新DeleteLog
,只要一次删除多个条目,我就会收到以下异常:
Uncaught PHP Exception Symfony\Component\Debug\Exception\FatalThrowableError: "Type error: Argument 2 passed to Doctrine\DBAL\Connection::delete() must be of the type array, null given
如何解决这个问题?为什么在刷新实体管理器时,postRemove
侦听器中创建的日志不会保留?
答案 0 :(得分:0)
我认为问题在于您要创建和删除多个Contact
实体,但是您在错误的事件中执行此操作,因为正如documentation中所述
实体发生后,实体发生postRemove事件 删除。它将在数据库删除操作后调用。它 没有调用DQL DELETE语句。
并且您不应对stated here
对数据库进行任何更改postUpdate,postRemove,postPersist
在EntityManager#flush()中调用三个post事件。变化 在这里与数据库中的持久性无关,但是你 可以使用这些事件来更改非可持久化项目,例如非映射项目 字段,日志记录甚至不是直接关联的类 由Doctrine映射。
因此,我将整个postRemove
逻辑移至preRemove
事件,因为
当传递给每个实体时,会调用preRemove事件 EntityManager #remove()方法。它适用于所有协会 被标记为级联删除。