Uel*_*eli 74 orm entitymanager symfony doctrine-orm
[Doctrine\ORM\ORMException]
The EntityManager is closed.
Run Code Online (Sandbox Code Playgroud)
在插入数据后出现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();
Run Code Online (Sandbox Code Playgroud)
任何人都知道如何重新连接?
小智 61
我的解决方案
在做任何事之前检查:
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->entityManager->create(
$this->entityManager->getConnection(),
$this->entityManager->getConfiguration()
);
}
Run Code Online (Sandbox Code Playgroud)
将保存所有实体.但它对于特定类或某些情况很方便.如果你有一些注入了entitymanager的服务,它仍然会被关闭.
小智 34
Symfony 2.0:
$em = $this->getDoctrine()->resetEntityManager();
Run Code Online (Sandbox Code Playgroud)
Symfony 2.1+:
$em = $this->getDoctrine()->resetManager();
Run Code Online (Sandbox Code Playgroud)
Ald*_*nio 23
这是一个非常棘手的问题,因为至少对于Symfony 2.0和Doctrine 2.1,在关闭后不可能以任何方式重新打开EntityManager.
我发现克服这个问题的唯一方法是创建自己的DBAL Connection类,包装Doctrine并提供异常处理(例如,在将异常弹出到EntityManager之前重试几次).它有点hacky,我担心它会导致事务环境中的一些不一致(即,如果失败的查询处于事务中间,我不确定会发生什么).
这种方式的示例配置是:
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
Run Code Online (Sandbox Code Playgroud)
该课程应该或多或少地开始:
namespace Your\DBAL;
class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection {
// ...
}
Run Code Online (Sandbox Code Playgroud)
一个非常烦人的事情是你必须覆盖提供异常处理包装的Connection的每个方法.使用闭合可以缓解那里的一些痛苦.
Fra*_*ula 20
这就是我解释Doctrine "EntityManager关闭"的原因.问题.基本上每次出现异常(即重复密钥)时,Doctrine都会关闭实体管理器.如果您仍想与数据库进行交互,则必须通过调用JGrinonresetManager()提到的方法来重置实体管理器.
在我的应用程序中,我运行了多个RabbitMQ使用者,他们都在做同样的事情:检查数据库中是否存在实体,如果是,则返回它,如果不创建它然后返回它.在检查该实体是否已经存在并创建它之间的几毫秒内,另一个消费者碰巧做了同样的事情,并创建了丢失的实体,使另一个消费者招致了一个重复的密钥异常.
这导致了软件设计问题.基本上我想要做的是在一个事务中创建所有实体.这对大多数人来说可能是自然的,但在我的情况下肯定是概念错误的.考虑以下问题:我必须存储具有这些依赖关系的足球比赛实体.
现在,为什么场地创建应该与匹配在同一个交易中?可能是因为我刚刚收到一个新的场所,它不在我的数据库中所以我必须先创建它.但也可能是该场地可能会举办另一场比赛,因此另一位消费者可能会尝试同时创建它.所以我要做的是首先在单独的事务中创建所有依赖项,确保我在重复键异常中重置实体管理器.我会说匹配旁边的所有实体都可以定义为"共享",因为它们可能是其他消费者中其他交易的一部分.在那里没有"共享"的东西是匹配本身,不可能同时由两个消费者创建.所以在上一次交易中,我希望看到比赛以及两支球队和比赛之间的关系.所有这些都导致了另一个问题.如果重置实体管理器,则在重置之前检索到的所有对象都是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.
*/
Run Code Online (Sandbox Code Playgroud)
所以我认为应该这样做.
$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();
Run Code Online (Sandbox Code Playgroud)
我希望它有帮助:)
JGr*_*non 17
您可以重置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();
Run Code Online (Sandbox Code Playgroud)
Seb*_*eck 12
在Symfony 4.2+ 中你必须使用这个包:
composer require symfony/proxy-manager-bridge
Run Code Online (Sandbox Code Playgroud)
否则你会得到例外:
Resetting a non-lazy manager service is not supported. Declare the "doctrine.orm.default_entity_manager" service as lazy.
Run Code Online (Sandbox Code Playgroud)
你可以像这样重置 entityManager :
服务.yaml:
App\Foo:
- '@doctrine.orm.entity_manager'
- '@doctrine'
Run Code Online (Sandbox Code Playgroud)
.php:
use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManagerInterface;
try {
$this->entityManager->persist($entity);
$this->entityManager->flush();
} catch (DBALException $e) {
if (!$this->entityManager->isOpen()) {
$this->entityManager = $this->doctrine->resetManager();
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
我发现一篇关于这个问题的有趣文章
if (!$entityManager->isOpen()) {
$entityManager = $entityManager->create(
$entityManager->getConnection(), $entityManager->getConfiguration());
}
Run Code Online (Sandbox Code Playgroud)
小智 5
Symfony v4.1.6
学说 v2.9.0
处理在存储库中插入重复项
//begin of repo
/** @var RegistryInterface */
protected $registry;
public function __construct(RegistryInterface $registry)
{
$this->registry = $registry;
parent::__construct($registry, YourEntity::class);
}
Run Code Online (Sandbox Code Playgroud)
//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();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
84737 次 |
| 最近记录: |