Doctrine2如何在回滚后处理更新实体? (“EntityManager已关闭”)

时间:2013-11-27 15:58:13

标签: php symfony doctrine-orm doctrine

我正在尝试在事务中进行一些处理并保存有关潜在故障的信息,如下所示:

$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很难做到这一点:

    {li>

    flush部分中的catch{}会尝试同时隐藏明显错误的$report$specification对象,因此我可以clear entityManager,但随后......

  1. 如果我clear entityManager$report不再受其管理,那么我需要致电$em->merge($report)再次进行管理。显然,$user将保持不受管理,因此,学说会执行insert或抱怨persist cascade。所以我可以merge()整个图表(很糟糕)或close entityManager,但是......

  2. 如果我close entityManager我只能通过report重新检索$repo->find($id);个实例 - 但我不想这样做,那就是笨

  3. 我错过了什么吗?有没有其他方法来实现上述结果?我觉得Doctrine让事情变得简单。

2 个答案:

答案 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对象)