我正在尝试在事务中进行一些处理并保存有关潜在故障的信息,如下所示:
$conn->beginTransaction();
try
{
$report = $reportRepository->find($id);
$user = $report->getUser();
$specification = new Specification();
$entityManager->persist($specification);
throw new ProcessingWentWrongException();
$entityManager->flush();
$conn->commit();
}
catch(ProcessingWentWrongException $e)
{
$conn->rollback();
// Store error info:
$report->setState('error');
$entityManager->persist($report);
$entityManager->flush(); // all hell breaks loose in here
}
这看起来像是一种非常常见的模式,但是Doctrine很难做到这一点:
flush
部分中的catch{}
会尝试同时隐藏明显错误的$report
和$specification
对象,因此我可以clear
entityManager
,但随后......
如果我clear
entityManager
,$report
不再受其管理,那么我需要致电$em->merge($report)
再次进行管理。显然,$user
将保持不受管理,因此,学说会执行insert
或抱怨persist cascade
。所以我可以merge()
整个图表(很糟糕)或close
entityManager,但是......
如果我close
entityManager
我只能通过report
重新检索$repo->find($id);
个实例 - 但我不想这样做,那就是笨
我错过了什么吗?有没有其他方法来实现上述结果?我觉得Doctrine让事情变得简单。
答案 0 :(得分:5)
使用两名实体管理员。一个用于潜在的不安全操作,一个用于记录/报告另一个。
通常,您无法确保不会发生错误(在刷新数据库之前不会发生某些错误)。一旦它们发生,实体经理就会因业务而关闭。
这就是我的所作所为(摘自config.yml):
doctrine:
orm:
default_entity_manager: 'default'
entity_managers:
default:
mappings: { ... }
logging:
mappings: { ... }
对于正常操作,我使用默认的实体管理器,不需要更改代码。
对于元操作(如记录批量导入的进度或结果或类似内容),我显式获取'logging'
管理器并将其用于创建/更新日志/报告实体(仅适用于那些)。
答案 1 :(得分:1)
在此特定示例中,您要向Report
添加规范。你能这样吗?
$entityManager->clear("Your\Bundle\Entity\Specification");
然后按照你的建议去做:
// Store error info:
$report->setState('error');
$entityManager->persist($report);
$entityManager->flush(); // all hell breaks loose in here
另外,我认为对具有指定ID的对象执行persist
无效。 ($report
分支中的catch
对象)