EntityManager закрыт

[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(); 

Кто-нибудь знает, как подключиться?

Это очень сложная проблема, поскольку, по крайней мере, для Symfony 2.0 и Doctrine 2.1 невозможно каким-либо образом повторно открыть EntityManager после ее закрытия.

Единственный способ, с помощью которого я решил преодолеть эту проблему, – создать свой собственный class соединения DBAL, обернуть Doctrine и предоставить обработку исключений (например, несколько раз повторить попытку, прежде чем вывести исключение из 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 { // ... } 

Очень неприятно то, что вам нужно переопределить каждый метод подключения, предоставляя вашу обертку для обработки исключений. Использование закрытий может облегчить некоторую боль там.

Мое решение.

Прежде чем делать что-либо, проверьте:

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

Все объекты будут сохранены. Но это удобно для определенного classа или некоторых случаев. Если у вас есть некоторые услуги с инъецированным лицом-менеджером, он все равно будет закрыт.

Symfony 2.0 :

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

Symfony 2.1+ :

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

Вы можете перезагрузить 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(); 

Вот как я решил доктрину «EntityManager закрыт». вопрос. В основном каждый раз, когда есть исключение (т. Е. Дублирующийся ключ), Doctrine закрывает Entity Manager. Если вы все еще хотите взаимодействовать с базой данных, вам необходимо сбросить resetManager() Entity Manger, вызвав метод resetManager() как упоминалось JGrinon .

В моем приложении у меня было несколько пользователей RabbitMQ, которые все делали то же самое: проверяли, существовал ли объект в базе данных, если да, верните его, если не создать его, а затем вернуть. В течение нескольких миллисекунд между проверкой того, существовал ли этот объект и его создание, другой потребитель сделал то же самое и создал отсутствующий объект, делающий другого потребителя в двойном ключевом исключении.

Это привело к проблеме разработки программного обеспечения. В основном то, что я пытался сделать, это создание всех объектов в одной транзакции. Это может показаться естественным для большинства, но в моем случае было концептуально неправильным. Рассмотрим следующую проблему: мне пришлось хранить футбольную фигуру Match, которая имела эти зависимости.

  • группа (т.е. группа A, группа B …)
  • раунд (т. е. полуфинал)
  • место (стадион, на котором проводится матч)
  • статус соответствия (т.е. половина времени, полный рабочий день)
  • две команды играют в матч
  • сам матч

Итак, почему создание места должно быть в той же транзакции, что и в матче? Может быть, я только что получил новое место, что его нет в моей базе данных, поэтому я должен его создать в первую очередь. Но также может случиться так, что в этом месте может быть другой матч, поэтому другой потребитель, вероятно, попытается создать его одновременно. Поэтому мне нужно было сначала создать все зависимости в отдельных транзакциях, чтобы я сбросил диспетчер объектов в дубликат ключевого исключения. Я бы сказал, что все сущности, находящиеся рядом с матчем, могут быть определены как «общие», поскольку они потенциально могут быть частью других транзакций у других потребителей. Что-то, что не «разделено», есть сам матч, который вряд ли будет создан двумя пользователями одновременно. Поэтому в последней транзакции я ожидаю увидеть только матч и связь между двумя командами и результатом. Все это также привело к еще одному вопросу. Если вы сбросите Entity Manager, все объекты, которые вы получили до сброса, для Doctrine полностью новы. Поэтому Doctrine не будет пытаться запустить UPDATE, но 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); $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(); в $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(); в $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(); в $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(); в $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(); в $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(); 

Я надеюсь, что это помогает 🙂

В controllerе.

Exception закрывает Entity Manager. Это создает проблемы для объемной вставки. Чтобы продолжить, нужно переопределить его.

 /** * @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++; } } } 

Попробуйте использовать:

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

перед началом транзакции.

On Connection::rollback проверяет свойство nestTransactionsWithSavepoints .

Это действительно старая проблема, но у меня была аналогичная проблема. Я делал что-то вроде этого:

 // 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 закрыт.

В моем случае решение заключалось в том, чтобы просто прояснить отдельный тип Entity и оставить $entityOne еще под EM:

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

Для чего я считаю, что эта проблема произошла в команде пакетного импорта из-за того, что цикл try / catch обнаруживает ошибку SQL (с em->flush() ), о которой я ничего не делал. В моем случае это было потому, что я пытался вставить запись с не-nullable свойством, оставленным как null.

Обычно это может привести к критическому исключению, и команда или controller должны остановиться, но я просто зарегистрировал эту проблему и продолжаю. Ошибка SQL заставила менеджера объектов закрыть.

Проверьте файл dev.log на любые глупые ошибки SQL, подобные этому, поскольку это может быть вашей ошибкой. 🙂

У меня была эта проблема. Это как я ее исправил.

Соединение, похоже, закрывается, пытаясь сброситься или сохраниться. Попытка возобновить его – это плохой выбор, потому что создает новые проблемы. Я попытался понять, почему соединение было закрыто, и обнаружил, что я делаю слишком много изменений до того, как это будет продолжаться.

persist () ранее решила проблему.

 // 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(); 

Я столкнулся с такой же проблемой. Посмотрев на несколько мест, я понял, как это с ним связано.

 //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(); } 

Надеюсь, это поможет кому-то!

  • Как интегрировать Ajax с Symfony2
  • MySQL Нелегальное сочетание сортировок
  • Должно ли все действительно быть связкой в ​​Symfony 2.x?
  • Аутентификация нескольких брандмауэров Symfony2 с одной формой входа
  • Как указать область действия API Google для получения дня рождения
  • Как использовать Ajax в формах администрирования Sonata?
  • Symfony 2: множественное и динамическое подключение к базе данных
  • Symfony2 - Как получить доступ к именам динамических переменных в веточке
  • Как добавить пользовательскую ссылку или кнопку в панель управления SonataAdminBundle в Symfony2
  • Как просмотреть настройки конфигурации из Symfony2 config.yml?
  • Сгенерировать новый токен CSRF без перезагрузки всей формы
  • Давайте будем гением компьютера.