EntityManager中被关闭(The EntityManager is closed)

2019-07-18 01:59发布

[Doctrine\ORM\ORMException]   
The EntityManager is closed.  

之后我插入数据时获得DBAL例外的,但EntityManager关闭,我不能够重新连接。

我想这样的,但它并没有得到一个连接。

$this->em->close();
$this->set('doctrine.orm.entity_manager', null);
$this->set('doctrine.orm.default_entity_manager', null);
$this->get('doctrine')->resetEntityManager();
$this->em = $this->get('doctrine')->getEntityManager();

任何一个知道如何重新连接?

Answer 1:

这是一个非常棘手的问题,因为,至少在Symfony的2.0和2.1学说,它是不可能以任何方式重新打开的EntityManager它关闭之后。

我发现解决这个问题的唯一方法是创建自己的DBAL Connection类,包装学说之一,(弹出异常出了EntityManager之前如重试几次)提供异常处理。 这是一个有点哈克,我恐怕会导致交易环境有些不一致(即我真的不知道,如果失败的查询是在一个事务中会发生什么)。

一个例子配置去为这种方式:

doctrine:
  dbal:
    default_connection: default
    connections:
      default:
        driver:   %database_driver%
        host:     %database_host%
        user:     %database_user%
        password: %database_password%
        charset:  %database_charset%
        wrapper_class: Your\DBAL\ReopeningConnectionWrapper

该类应该开始或多或少是这样的:

namespace Your\DBAL;

class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection {
  // ...
}

一个很烦人的事情是,你必须重载连接提供您的异常处理包装的每个方法。 使用闭包可以有缓解一些痛苦。



Answer 2:

我的解决办法。

做任何事情前检查:

if (!$this->entityManager->isOpen()) {
    $this->entityManager = $this->entityManager->create(
        $this->entityManager->getConnection(),
        $this->entityManager->getConfiguration()
    );
}

所有实体将被保存。 但它是非常方便的某一类或某些情况下。 如果你有注入EntityManager的一些服务,但它仍然被关闭。



Answer 3:

Symfony的2.0:

$em = $this->getDoctrine()->resetEntityManager();

Symfony的2.1+:

$em = $this->getDoctrine()->resetManager();


Answer 4:

您可以重置您的EM所以

// reset the EM and all aias
$container = $this->container;
$container->set('doctrine.orm.entity_manager', null);
$container->set('doctrine.orm.default_entity_manager', null);
// get a fresh EM
$em = $this->getDoctrine()->getManager();


Answer 5:

这是我如何解决教义“EntityManager中被关闭。” 问题。 基本上每个有(即重复键)学说关闭实体管理器异常的时间。 如果你仍想与数据库进行交互,你必须通过调用重置实体管理器resetManager()方法,通过JGrinon提及。

在我的应用程序正在运行多个RabbitMQ的消费者,都做同样的事情:检查是否一个实体是存在于数据库中,如果是退货,如果没有创建它,然后返回。 在检查是否该实体已经存在,创建它的几毫秒另一消费者碰巧做同样创造缺失实体使得其他消费的重复键异常承担。

这导致了软件设计的问题。 基本上我试图做的是在一个事务中创建所有的实体。 这可能会感到自然的大多数,但肯定是在我的情况在概念上是错误的。 考虑下面的问题:我不得不存储其中有这些依赖足球比赛实体。

  • 一组(即A组,B组...)
  • 圆(即,半决赛)
  • 场地(即体育场在比赛正在发生)
  • 匹配状态(即半时间,全职)
  • 两队打比赛
  • 比赛本身

现在,为什么场地创作应该在相同的事务匹配? 这可能是因为我刚收到一个新的场地,这不是我的数据库,所以我必须先创建它。 但是,这也可能是因为该场地可举办另一场比赛中,以便另一消费者可能会尝试在同一时间将其创建为好。 因此,我所要做的就是在确保我是在重复键异常复位实体管理器分离交易的可先创建所有的依赖。 我想说的是,在有比赛的旁边所有的实体可以被定义为“共享”,因为他们可能是其他消费者的其他交易的一部分。 在那里,是不是“共享”的东西是不太可能被两个消费者在同一时间创造了比赛本身。 所以在最后的事务我期望看到的只是比赛和两支球队和比赛之间的关系。 所有这一切也导致了另一个问题。 如果重置实体管理器,你已经复位前检索到的所有对象都是教义全新的。 因此主义不会试图对他们,但一个INSERT运行的更新 ! 因此,请确保您创建逻辑上是正确的交易所有的依赖关系,然后将它们设置为目标实体之前检索所有对象从数据库返回的。 考虑下面的代码作为示例:

$group = $this->createGroupIfDoesNotExist($groupData);

$match->setGroup($group); // this is NOT OK!

$venue = $this->createVenueIfDoesNotExist($venueData);

$round = $this->createRoundIfDoesNotExist($roundData);

/**
 * If the venue creation generates a duplicate key exception
 * we are forced to reset the entity manager in order to proceed
 * with the round creation and so we'll loose the group reference.
 * Meaning that Doctrine will try to persist the group as new even
 * if it's already there in the database.
 */

因此,这是如何,我认为它应该做的事。

$group = $this->createGroupIfDoesNotExist($groupData); // first transaction, reset if duplicated
$venue = $this->createVenueIfDoesNotExist($venueData); // second transaction, reset if duplicated
$round = $this->createRoundIfDoesNotExist($roundData); // third transaction, reset if duplicated

// we fetch all the entities back directly from the database
$group = $this->getGroup($groupData);
$venue = $this->getVenue($venueData);
$round = $this->getGroup($roundData);

// we finally set them now that no exceptions are going to happen
$match->setGroup($group);
$match->setVenue($venue);
$match->setRound($round);

// match and teams relation...
$matchTeamHome = new MatchTeam();
$matchTeamHome->setMatch($match);
$matchTeamHome->setTeam($teamHome);

$matchTeamAway = new MatchTeam();
$matchTeamAway->setMatch($match);
$matchTeamAway->setTeam($teamAway);

$match->addMatchTeam($matchTeamHome);
$match->addMatchTeam($matchTeamAway);

// last transaction!
$em->persist($match);
$em->persist($matchTeamHome);
$em->persist($matchTeamAway);
$em->flush();

我希望它能帮助:)



Answer 6:

在控制器。

异常关闭实体管理器。 这使得批量插入烦恼。 要继续,需要重新定义它。

/** 
* @var  \Doctrine\ORM\EntityManager
*/
$em = $this->getDoctrine()->getManager();

foreach($to_insert AS $data)
{
    if(!$em->isOpen())
    {
        $this->getDoctrine()->resetManager();
        $em = $this->getDoctrine()->getManager();
    }

  $entity = new \Entity();
  $entity->setUniqueNumber($data['number']);
  $em->persist($entity);

  try
  {
    $em->flush();
    $counter++;
  }
  catch(\Doctrine\DBAL\DBALException $e)
  {
    if($e->getPrevious()->getCode() != '23000')
    {   
      /**
      * if its not the error code for a duplicate key 
      * value then rethrow the exception
      */
      throw $e;
    }
    else
    {
      $duplication++;
    }               
  }                      
}


Answer 7:

对于什么是值得,我发现这个问题在批量导入命令发生,因为一个try / catch循环捕获SQL错误的(与em->flush()我没有做任何事情。 在我的情况,那是因为我试图插入一条记录与非空的财产留给空。

通常,这会导致一个重要的例外发生,命令或控制器停止,但我只是记录这个问题,而不是与继承。 SQL错误造成了实体管理器来关闭。

检查dev.log对于任何像这样愚蠢的SQL错误的文件,因为它可能是你的错。 :)



Answer 8:

尝试使用:

$em->getConnection()->[setNestTransactionsWithSavepoints][1](true);

前开始交易。

Connection::rollback方法是检查nestTransactionsWithSavepoints财产。



Answer 9:

我有这个问题。 这怎么我固定它。

连接似乎关闭,而试图冲洗或持续。 试图重新打开它是一个糟糕的选择,因为创造了新的问题。 我tryed理解为什么连接被关闭,发现我在做太多的修改坚持了。

一直存在()较早地解决了问题。



Answer 10:

这的确是老问题,但我只是有类似的问题。 我在做这样的事情:

// entity
$entityOne = $this->em->find(Parent::class, 1);

// do something on other entites (SomeEntityClass)
$this->em->persist($entity);
$this->em->flush();
$this->em->clear();

// and at end I was trying to save changes to first one by
$this->em->persist($entityOne);
$this->em->flush();
$this->em->clear();

问题是明确分离的所有实体,包括第一个扔错误的EntityManager被关闭。

在我的情况的解决方案是只是做不同类型的实体清楚,并留下$entityOne仍然EM下:

$this->em->clear(SomeEntityClass::class);


Answer 11:

Symfony的v4.1.6

学说v2.9.0

过程重复插入在储存库中

  1. 可以访问你的回购注册表

 //begin of repo /** @var RegistryInterface */ protected $registry; public function __construct(RegistryInterface $registry) { $this->registry = $registry; parent::__construct($registry, YourEntity::class); } 

  1. 裹危险代码为交易和异常的情况下休息经理

 //in repo method $em = $this->getEntityManager(); $em->beginTransaction(); try { $em->persist($yourEntityThatCanBeDuplicate); $em->flush(); $em->commit(); } catch (\Throwable $e) { //Rollback all nested transactions while ($em->getConnection()->getTransactionNestingLevel() > 0) { $em->rollback(); } //Reset the default em if (!$em->isOpen()) { $this->registry->resetManager(); } } 



Answer 12:

我发现这个问题的有趣文章

if (!$entityManager->isOpen()) {
  $entityManager = $entityManager->create(
    $entityManager->getConnection(), $entityManager->getConfiguration());
}

教义2异常的EntityManager被关闭



Answer 13:

// first need to reset current manager
$em->resetManager();
// and then get new
$em = $this->getContainer()->get("doctrine");
// or in this way, depending of your environment:
$em = $this->getDoctrine();


Answer 14:

我面临着同样的问题。 看着几个地方后,这里是我如何处理它。

//function in some model/utility
function someFunction($em){
    try{
        //code which may throw exception and lead to closing of entity manager
    }
    catch(Exception $e){
        //handle exception
        return false;
    }
    return true;
}

//in controller assuming entity manager is in $this->em 
$result = someFunction($this->em);
if(!$result){
    $this->getDoctrine()->resetEntityManager();
    $this->em = $this->getDoctrine()->getManager();
}

希望这可以帮助别人!



文章来源: The EntityManager is closed