【发布时间】:2020-01-07 17:38:25
【问题描述】:
我正在寻找一种将 UnitOfWork 恢复到干净状态的方法,而无需清除整个事情。我仍然想访问我已加载的实体。这是我所拥有的基础,但我不确定这是否会以奇怪的方式破坏教义。
$uow = $em->getUnitOfWork();
$uow->computeChangeSets();//Can this be called once here, or should it be called in the inside loop so we get fresh information after a potential cascading refresh or persist?
foreach ($uow->getIdentityMap() as $className => $entities) {
foreach ($entities as $oid => $entity) {
if ($uow->isEntityScheduled($entity)) {
if ($uow->isScheduledForInsert($entity)) {
$uow->scheduleForDelete($entity);//Removes from the insert list without cascading delete or calling removal events
} elseif ($uow->isScheduledForUpdate($entity)) {
$em->refresh($entity);
} elseif ($uow->isScheduledForDelete($entity)) {
$em->persist($entity);
$em->refresh($entity);//Should I re-call computeChangeSets() here so I can check if the entity is now scheduled for update?
}
}
}
}
对于上下文:我正在运行批处理操作,在处理每条记录后,我会保留任何需要的更改。如果一条记录因错误而失败,则会处理该失败,但它可能会因此类异常而中断批处理的其余部分:
A new entity was found through the relationship FOO#bar that was not configured to cascade persist operations for entity: otherFooBar .
由于如果记录失败,我不需要保存处理记录的任何更改,因此我想简单地清理所有更改并保持对象图完整,同时继续处理批处理。
我已经阅读了教义的源代码,看起来这应该可以正常工作,但我对 Doctrine 的内部结构并不十分熟悉。有没有人看到或知道这种方法的缺陷/陷阱,或者知道实现此目的的更好方法?
编辑:澄清这个问题背后的原因。
当处理记录时发生错误时,这可能会使 UoW / EntityManger 处于无法在不被清除的情况下继续存在的位置。在我的特定情况下,错误使现有的已更改实体具有链接非持久实体,其中关系未配置为级联持久,这导致所有后续持久失败。此时,如果我想继续处理批处理并跳过失败的记录,我有两个选择:
1) 清除 EntityManager 并从数据库中重新加载所有业务逻辑实体。但这意味着恢复功能不能是通用的,必须自定义才能知道每次更改时要重新加载和调整哪些实体。
2) 使用 UnitOfWork 的现有功能清理 EntityManager,这允许代码是通用的并且不需要持续修改。
【问题讨论】:
-
我已经通过
refresh()ing 循环中更改的实体“解决”了这个问题。仍然容易出错,因为如果您在主循环中编辑代码,您可能还必须添加/删除/更新清理代码(即代码,可能在 catch() 子句中,它执行refresh())。这种耦合不是很明显。我很惊讶 Doctrine 本身没有任何回滚。 -
@hbogert 如果您查看问题中的示例代码,我确实对计划更新或删除的实体使用刷新。我认为刷新不适用于计划持久化的新实体。
标签: php symfony doctrine-orm