【问题标题】:How to update and persist entity after the entity manager was closed due to an exception and then re-opend?实体管理器因异常关闭并重新打开后如何更新和持久化实体?
【发布时间】:2022-12-16 09:13:35
【问题描述】:

我正在从事一个基于 Symfony + Doctrine 的项目。当长时间运行的导入操作(解析数据、创建实体、持久化实体等)期间发生异常时,实体管理器关闭.

我还尝试重新打开实体管理器,但我无法正确使用它,并且在尝试保留其他实体时得到 EntityNotFoundExceptionORMInvalidArgumentException

那么:如何正确地重新打开一个关闭的实体管理器以便能够再次使用它?


细节:

  • 为避免其他用户操作与正在运行的导入发生冲突,用户帐户在导入开始前被锁定。
  • 这是通过从数据库查询当前用户的 ImportLock 实体来完成的。如果不存在这样的锁,则会创建一个新实体。锁定设置为活动并持久。如果活动锁已经存在,则另一个导入处于活动状态并且不会启动当前导入。
  • transaction 开始处理导入
  • 解析导入数据,创建并保存实体
  • 如果一切正常,则提交事务并将锁设置为非活动状态。完毕。
  • 但是,当导入已经存在的数据时,会抛出 UniqueConstraintViolationException关闭实体管理器.
  • 虽然捕获到异常并重置实体,但无法更新锁定实体。

代码:

$lockRepo = $this->entityManager->getRepository(ImportLock::class);
$lock = $lockRepo->findOneByUser($user);

if (!$lock) {
    $lock = new ImportLock();
}

if ($lock->isActive()) {
    // Import already running --> cancel
    return;
}

$lock->setActive();
$this->entityManager->persist($lock);
$this->entityManager->flush();


// Import
try {
    $this->entityManager->getConnection()->beginTransaction();
    doImport();
    $this->entityManager->getConnection()->commit();
} catch (\Exception $e) {
    $this->entityManager->getConnection()->rollback();

    if (!$this->entityManager->isOpen()) {
        // Step 1
        $this->doctrineRegistry->resetManager();

        // Step 2
        $lockRepo = $this->entityManager->getRepository(ImportLock::class);
        $lock = $lockRepo->findOneById($lock->getId()); // look up entity using Id to avoid using the $user which was handled by the "old" entity manager
    }
} finally {
    $lock->setInactive();
    $this->entityManager->persist($lock);  // <-- Exception
    $this->entityManager->flush();
} 

根据我的尝试,我在尝试保留锁时会遇到不同的异常:

  • Doctrine\ORM\Exception\EntityManagerClosed 当实体管理器未重新打开/重置时(未执行第 1 步和第 2 步)
  • Doctrine\\ORM\\EntityNotFoundException(code: 0): Unable to find "My\\Entity\\User\" entity identifier associated with the UnitOfWork 重置实体管理器后未重新加载 $lock(未执行第 2 步)
  • Doctrine\\ORM\\ORMInvalidArgumentException(code: 0): A new entity was found through the relationship 'My\\Entity\\ImportLock#user' that was not configured to cascade persist operations for entity: My\\Entity\\User@621 重置实体管理器并重新加载$lock(执行第 1 步和第 2 步)。

似乎以某种方式使用“旧”实体管理器查询/创建的$lock 无法与“新”(重新打开)实体管理器一起正确使用。

如何解决这个问题?

【问题讨论】:

  • 您是否尝试过显式设置事务并且在出现异常的情况下,除了回滚之外您还解锁记录!?

标签: symfony doctrine entitymanager


【解决方案1】:

我遇到了同样的问题,我刚刚创建了一个 catch 并启动了一个新的 EntityManager 来重新创建存储库,并且我一直保留一个数据列表:

catch (EntityManagerClosed $e) {
            $em = new EntityManager($em->getConnection(), $em->getConfiguration());
            $repository = $em->getRepository(Class::class);
} 

【讨论】:

    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多