在Doctrine ORM中的UniqueConstraintViolationException之后继续持久化实体?

时间:2017-05-05 00:22:04

标签: symfony doctrine-orm

我试图在UniqueConstraintViolationException之后继续持久化实体

我使用Doctrine ORM实体上传代码列表并保存到数据库中。

我想避免重复的代码并继续保存其他代码。

首先查询代码是否在数据库中然后保存的简单解决方案是可以的但只是忽略异常并继续?避免查询数据库。

foreach($uploadEntities as $entity){ 
 try{
   $em->persist($entity);
 }catch(UniqueConstraintViolationException){
   //ignore  
 }
}

2 个答案:

答案 0 :(得分:3)

你必须在$em->flush()电话上抓住例外。

考虑在这样的异常之后,事务被回滚并且实体管理器被关闭。

然后你应该用

重新打开它
    $em = $this->getDoctrine()->resetManager();

但请注意,作为此过程的结果,EntityManager的所有先前管理或删除的实例都将分离。分离对象的状态将是事务回滚时的状态。对象的状态绝不会回滚,因此对象现在与数据库不同步。应用程序可以继续使用分离的对象,因为它们的状态可能不再准确。

因此,您应该从dB中重新获取您需要处理的所有先前提取的对象。

分别刷新每个持久化对象可能很方便,这样你就可以跳过Bad对象并继续。

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/transactions-and-concurrency.html#exception-handling

答案 1 :(得分:1)

我的建议是不要使用这种类型的工作流,出于性能原因,最好检查数据库中所有现有代码,然后忽略现有代码。

$em->createQueryBuilder()
          ->select('code.code')
          ->from(Code::class, 'code')
          ->where($qb->expr()->in('code.code', $importedCodes));

$existentCodes = array_column($qb->getQuery()->getArrayResult(), 'code');
if (in_array($currentCode, $existentCodes)){
     continue;
}
另一方面,

可以在事务中包装这种类型的进程。如果要上传许多代码,请使用批处理或其他任何代码来提高性能。