本文介绍了看来我有两个学说实体经理,但我只想要一个! o.O的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我花了最后几天解决我的捆绑中的一个非常微妙的错误。 实际上我得到一个作业实体。该实体与属性作业实体之间具有一对一的自引用关系$ c> retryOf 。 当我尝试更新检索到的作业#状态属性,我得到以下异常抛出:最后我发现我用来检索和持久化/刷新实体的 EntityManager 与我的实体不同,用于管理自己和检索相关实体。 所以,我的问题是:假设我注入正确的我的服务中的EntityManager ( @ doctrine.orm.default_entity_manager ): 为什么我的服务使用一个,存储库使用另一个? 如何使我的实体使用相同的注入服务? (或者如何注入我的实体使用的相同)相同)? 我如何注意 EntityManager services: queues: class:SerendipityHQ\ Bundle\CommandsQueuesBundle\Service\QueuesManager 参数:[@ commands_queues.do_not_use.entity_manager] #此服务是由QueuesRunCommand私有使用 commands_queues.do_not_use.daemon : class:SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesDaemon 参数:[@ commands_queues.do_not_use.entity_manager] EntityManager 是在 SHQCommandsQueuesExtension (请参阅GitHub上的代码)。 p> 问题em真的很难,因为我收到错误,但我不能再坚持服务使用的实体经理:这导致数据库中的行重复。 如何指定 JobRepository CLASS / ** *基本属性和方法oa Job。 * * @ ORM\Entity(repositoryClass =SerendipityHQ\Bundle\CommandsQueuesBundle\Repository\JobRepository) * @ ORM\Table(name =queues_scheduled_jobs ) * / class Job { ... } / ** * {@inheritdoc} * / 类JobRepository扩展EntityRepository { / ** * @param int $ id * * @return null |对象| Job * / public function findOneById(int $ id) { return parent :: findOneBy(['id'=> $ id]); } / ** *返回可以运行的作业。 * *如果将来没有startDate,并且其父作业已经以 * success结束,则可以运行作业。 * * @return null | Job * / public function findNextRunnableJob() { //收集必须排除的作业下一个findNextJob()调用 $ excludedJobs = []; while(null!== $ job = $ this-> findNextJob($ excludedJobs)){ //如果可以运行... if(false === $ job-> hasNotFinishedParentJobs()){ // ...返回 return $ job; } //作业无法运行或无法获取锁定 $ excludedJobs [] = $ job-> getId(); //从实体管理器中删除它以释放一些内存 $ this-> _em-> detach($ job); } } / ** *查找要处理的下一个作业。 * * @param array $ excludedJobs必须从SELECT * * @return作业中排除的作业| null * / private function findNextJob(array $ excludedJobs = []) { $ queryBuilder = $ this-> getEntityManager() - > createQueryBuilder(); $ queryBuilder-> select('j') - > from('SHQCommandsQueuesBundle:Job','j') - > orderBy('j.priority','ASC') - > addOrderBy('j.createdAt','ASC') //状态必须是NEW - > where($ queryBuilder-> expr() - > eq ('j.status',':status')) - > setParameter('status',Job :: STATUS_NEW) //它没有一个executeAfterTime设置或设置的时间过去是 - > andWhere( $ queryBuilder-> expr() - > orX( $ queryBuilder-> expr() - > isNull('j.executeAfterTime'), $ queryBuilder-> expr() - > lt('j.executeAfterTime',':now'))) - > setParameter('now',new \DateTime ), '约会时间'); //如果有排除的作业... if(false === empty($ excludedJobs)){ //该ID不是其中之一 $ queryBuilder-> andWhere( $ queryBuilder-> expr() - > notIn('j.id',':excludedJobs')) - > setParameter 'excludedJobs',$ excludedJobs,Connection :: PARAM_INT_ARRAY); } return $ queryBuilder-> getQuery() - > setMaxResults(1) - > getOneOrNullResult(); } } 存储库仅在 c code code code code code code code code code code code $ c > 验证两个 EntityManager 不同 测试1。再次在 EntityManager 中继续使用我在服务中使用:作品,不再抛出异常 这将强制我做这样的事情: ... // SerendipityHQ\Bundle\ CommandsQueuesBundle\Service\QueuesDaemon if($ job-> isRetry()){ //这里我必须在我注入的实体管理器中坚持AGAIN由Job#retryOf $ b $引用的Entity b $ this-> entityManager-> persist($ job-> getRetryOf()); ... } ... 如果我不这样做,则再次抛出异常。 所以似乎注释使用 EntityManager 和我的服务加载实体,而是使用我指定的实体管理器这是非常奇怪的,从来没有发生过我! OO TEST 2. VarDump :显示两个不同的唯一标识符 使用简单的 VarDumper :: dump($ passedEntityManager)和 VarDumper :: dump($ entity)我发现他们使用两个不同的实体经理: ... // SerendipityHQ \Bundle\CommandsQueuesBundle\Service\QueuesDaemon if($ job-> isRetry()){ // $ job-> setRetryOf($ this-> entityManager-> getRepository( 'SHQCommandsQueuesBundle:作业') - > findOneById($求职> getRetryOf() - >的getId())); VarDumper :: dump($ this-> entityManager); VarDumper :: dump($ job); 死 ... } ... 结果是: EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ORM\EntityManager {#768 -delegate:DoctrineORMEntityManager_000000007aac762a000000007cf8d85284b5df468960200ce73b9230d68d81c1 {#773 ... 2} -container:appDevDebugProjectContainer {#495 ... 12} -config:null -conn:null -metadataFactory:null -unitOfWork:null -eventManager:null -proxyFactory:null -repositoryFactory:null -expressionBuilder:null -closed:false -filterCollection:null -cache:null } SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Job {#730 -id:3 。 .. -childDependencies:Doctrine\ORM\PersistentCollection {#41028 ... -em:Doctrine\ORM\EntityManager {#788 ... 11} ... #initialized:true } -parentDependencies:Doctrine\ORM\PersistentCollection {#41019 ... -em :Doctrine\ORM\EntityManager {#788 ... 11} ... #initialized:true } ... -processedBy:SerendipityHQ \\ Bundle\CommandsQueuesBundle\Entity\Daemon {#806 ... -processedJobs:Doctrine\ORM\PersistentCollection {#819 ... - em:Doctrine\ORM\EntityManager {#788 ... 11} ... #initialized:true } } ... -childDependencies:Doctrine\ORM\PersistentCollection {#40899 ... -em:Doctrine\ORM\EntityManager {#788 ... 11} ... #initialized:false } -parentDependencies:Doctrine\ORM\PersistentCollection {#40901 ... -em:Doctrine\ORM\Entity经理{#788 ... 11} ... #initialized:true } ... } 实体经理是#788 : SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Job {#725 -id:3 -command:queues:test ... -childDependencies:Doctrine\ORM\PersistentCollection {#41028 -snapshot:[] -owner:SerendipityHQ\\ \\ Bundle\CommandsQueuesBundle\Entity\Job {#725} -association:array:16 [... 16] -em:Doctrine\ORM\EntityManager {#788 ... 11} 而我注入的实体经理是 768 : EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ORM\EntityManager {#768 -delegate:DoctrineORMEntityManager_000000007aac762a000000007cf8d85284b5df468960200ce73b9 230d68d81c1。 {#773 ... 2} 测试3.证明我有不止一个 EntityManager :我有 Aerendir $ app / console debug:container | grep EntityManager aws_ses_monitor.entity_manager Doctrine\ORM\EntityManager commands_queues.do_not_use.entity_manager Doctrine\ORM\EntityManager doctrine.orm.default_entity_manager EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ ORM\EntityManager stripe_bundle.entity_manager Doctrine\ORM\EntityManager 这是正确的因为我实际上有4个实体经理,而那些报告的是我期望存在的。 TEST 4.确定哪个 EntityManager 被我的服务使用,哪个在我的仓库中使用 // SerendipityHQ\Bundle\CommandsQueuesBundle\ Service\QueuesDaemon if($ job-> isRetry()){ VarDumper :: dump('entityManager'); VarDumper :: dump(spl_object_hash($ this-> entityManager)); VarDumper :: dump('aws_ses_monitor.entity_manager'); VarDumper :: dump(spl_object_hash($ this-> container-> get('aws_ses_monitor.entity_manager'))); VarDumper :: dump('commands_queues.do_not_use.entity_manager'); VarDumper :: dump(spl_object_hash($ this-> container-> get('commands_queues.do_not_use.entity_manager'))); VarDumper :: dump('doctrine.orm.default_entity_manager'); VarDumper :: dump(spl_object_hash($ this-> container-> get('doctrine.orm.default_entity_manager'))); VarDumper :: dump('stripe_bundle.entity_manager'); VarDumper :: dump(spl_object_hash($ this-> container-> get('stripe_bundle.entity_manager'))); die; ... } 在 JobRepository 类中: 私有函数findNextJob(array $ excludedJobs = []) { VarDumper :: dump('Inside repository') ; VarDumper :: dump(spl_object_hash($ this-> getEntityManager())); ... 结果: 00000000326f44a000000000730f8ec4entityManager00000000326f44b400000000730f8ec4aws_ses_monitor.entity_manager 00000000326f44b400000000730f8ec4commands_queues.do_not_use.entity_manager00000000326f44b400000000730f8ec4doctrine.orm.default_entity_manager00000000326f44b400000000730f8ec4stripe_bundle.entity_manager00000000326f44b400000000730f8ec4 这是一回事!这真的是意想不到的!如果 EntityManager 是一样的: 为什么 Job#retryOf 对象尚未持久化,我必须再次坚持不要抛出异常? 为什么 VarDumper 给我两个不同的内部对象句柄如果对象是一样的? 解决方案 测试5。尝试删除所有调用 $ this-> entityManager-> detach() 解决!问题是一个 detach(),没有检查状态:如果一个作业失败,我只是分离它在$ code> EntityManager 中没有浮动,随着捆绑启动守护进程,我需要释放内存。但是,只有当 Job 绝对失败时,才需要解除它,而如果必须重试,那么我不需要分离它,或至少我有如果处理 Job 指的是重新加载... 建立一个守护进程需要很多注意细节! I've spent last days solving a very subtle bug in my bundle.Practically I get a Job entity from the database. This entity has a one-to-one, self-referencing relation to another Job entity on the property retryOf.When I try to update the retrieved Job#status property, I get the following exception thrown:In the end I discovered that the EntityManager I use to retrieve and persist/flush entities is different from the one used by my entities to manage themselves and retrieve related entities.So, my question is: assuming I'm injecting the right EntityManager in my services (@doctrine.orm.default_entity_manager):Why my services use one and the repositories use another?How can I make my entities use the same I inject in services? (or how can I inject the same used by my entities - is the same)?HOW I INJECT THE EntityManagerservices: queues: class: SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesManager arguments: ["@commands_queues.do_not_use.entity_manager"] #This service is meant to be privately used by QueuesRunCommand commands_queues.do_not_use.daemon: class: SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesDaemon arguments: ["@commands_queues.do_not_use.entity_manager"]The EntityManager is created in the SHQCommandsQueuesExtension (see its code on GitHub).The problem is really hard, as I receive the error but I cannot persist again in the entity manager used by services: this cause a duplication of rows in the database!HOW I SPECIFY THE JobRepository CLASS/** * Basic properties and methods o a Job. * * @ORM\Entity(repositoryClass="SerendipityHQ\Bundle\CommandsQueuesBundle\Repository\JobRepository") * @ORM\Table(name="queues_scheduled_jobs") */class Job{...}/** * {@inheritdoc} */class JobRepository extends EntityRepository{ /** * @param int $id * * @return null|object|Job */ public function findOneById(int $id) { return parent::findOneBy(['id' => $id]); } /** * Returns a Job that can be run. * * A Job can be run if it hasn't a startDate in the future and if its parent Jobs are already terminated with * success. * * @return null|Job */ public function findNextRunnableJob() { // Collects the Jobs that have to be excluded from the next findNextJob() call $excludedJobs = []; while (null !== $job = $this->findNextJob($excludedJobs)) { // If it can be run... if (false === $job->hasNotFinishedParentJobs()) { // ... Return it return $job; } // The Job cannot be run or its lock cannot be acquired $excludedJobs[] = $job->getId(); // Remove it from the Entity Manager to free some memory $this->_em->detach($job); } } /** * Finds the next Job to process. * * @param array $excludedJobs The Jobs that have to be excluded from the SELECT * * @return Job|null */ private function findNextJob(array $excludedJobs = []) { $queryBuilder = $this->getEntityManager()->createQueryBuilder(); $queryBuilder->select('j')->from('SHQCommandsQueuesBundle:Job', 'j') ->orderBy('j.priority', 'ASC') ->addOrderBy('j.createdAt', 'ASC') // The status MUST be NEW ->where($queryBuilder->expr()->eq('j.status', ':status'))->setParameter('status', Job::STATUS_NEW) // It hasn't an executeAfterTime set or the set time is in the past ->andWhere( $queryBuilder->expr()->orX( $queryBuilder->expr()->isNull('j.executeAfterTime'), $queryBuilder->expr()->lt('j.executeAfterTime', ':now') ) )->setParameter('now', new \DateTime(), 'datetime'); // If there are excluded Jobs... if (false === empty($excludedJobs)) { // The ID hasn't to be one of them $queryBuilder->andWhere( $queryBuilder->expr()->notIn('j.id', ':excludedJobs') )->setParameter('excludedJobs', $excludedJobs, Connection::PARAM_INT_ARRAY); } return $queryBuilder->getQuery()->setMaxResults(1)->getOneOrNullResult(); }}The repository is simply specified in the @Entity annotation in the Job entity class.TESTSProving the two EntityManagers are differentTEST 1. Persist again in the EntityManager I'm using in services: works, the exception is not thrown anymoreThis forces me to do something like this: ... // SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesDaemon if ($job->isRetry()) { // Here I have to persist AGAIN in my injected entity manager the Entity referenced by Job#retryOf $this->entityManager->persist($job->getRetryOf()); ... } ...If I don't do this, the exception is again thrown.So it seems that the annotations loads entities using an EntityManager and my service, instead, use the entity manager I've specified... This is very strange and never happened to me! O.OTEST 2. VarDump: Shows two different unique identifiersWith a simple VarDumper::dump($passedEntityManager) and VarDumper::dump($entity) I've discovered that they use two different entity managers: ... // SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesDaemon if ($job->isRetry()) { //$job->setRetryOf($this->entityManager->getRepository('SHQCommandsQueuesBundle:Job')->findOneById($job->getRetryOf()->getId())); VarDumper::dump($this->entityManager); VarDumper::dump($job); die; ... } ...The result is:EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ORM\EntityManager {#768 -delegate: DoctrineORMEntityManager_000000007aac762a000000007cf8d85284b5df468960200ce73b9230d68d81c1 {#773 …2} -container: appDevDebugProjectContainer {#495 …12} -config: null -conn: null -metadataFactory: null -unitOfWork: null -eventManager: null -proxyFactory: null -repositoryFactory: null -expressionBuilder: null -closed: false -filterCollection: null -cache: null}SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Job {#730 -id: 3 ... -childDependencies: Doctrine\ORM\PersistentCollection {#41028 ... -em: Doctrine\ORM\EntityManager {#788 …11} ... #initialized: true } -parentDependencies: Doctrine\ORM\PersistentCollection {#41019 ... -em: Doctrine\ORM\EntityManager {#788 …11} ... #initialized: true } ... -processedBy: SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Daemon {#806 ... -processedJobs: Doctrine\ORM\PersistentCollection {#819 ... -em: Doctrine\ORM\EntityManager {#788 …11} ... #initialized: true } } ... -childDependencies: Doctrine\ORM\PersistentCollection {#40899 ... -em: Doctrine\ORM\EntityManager {#788 …11} ... #initialized: false } -parentDependencies: Doctrine\ORM\PersistentCollection {#40901 ... -em: Doctrine\ORM\EntityManager {#788 …11} ... #initialized: true } ...}In entities the Entity manager is #788:SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Job {#725 -id: 3 -command: "queues:test"... -childDependencies: Doctrine\ORM\PersistentCollection {#41028 -snapshot: [] -owner: SerendipityHQ\Bundle\CommandsQueuesBundle\Entity\Job {#725} -association: array:16 [ …16] -em: Doctrine\ORM\EntityManager {#788 …11}while my injected entity manager is 768:EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ORM\EntityManager {#768 -delegate: DoctrineORMEntityManager_000000007aac762a000000007cf8d85284b5df468960200ce73b9230d68d81c1. {#773 …2}TEST 3. Proving I have more than one EntityManager: I haveAerendir$ app/console debug:container | grep EntityManager aws_ses_monitor.entity_manager Doctrine\ORM\EntityManager commands_queues.do_not_use.entity_manager Doctrine\ORM\EntityManager doctrine.orm.default_entity_manager EntityManager58a434fb99fbf_546a8d27f194334ee012bfe64f629947b07e4919\__CG__\Doctrine\ORM\EntityManager stripe_bundle.entity_manager Doctrine\ORM\EntityManager This is right as I effectively have 4 entity managers and the ones reported are the ones I expect exist.TEST 4. Identify which EntityManager is used by my services and which one is used in my repositories // SerendipityHQ\Bundle\CommandsQueuesBundle\Service\QueuesDaemon if ($job->isRetry()) { VarDumper::dump('entityManager'); VarDumper::dump(spl_object_hash($this->entityManager)); VarDumper::dump('aws_ses_monitor.entity_manager'); VarDumper::dump(spl_object_hash($this->container->get('aws_ses_monitor.entity_manager'))); VarDumper::dump('commands_queues.do_not_use.entity_manager'); VarDumper::dump(spl_object_hash($this->container->get('commands_queues.do_not_use.entity_manager'))); VarDumper::dump('doctrine.orm.default_entity_manager'); VarDumper::dump(spl_object_hash($this->container->get('doctrine.orm.default_entity_manager'))); VarDumper::dump('stripe_bundle.entity_manager'); VarDumper::dump(spl_object_hash($this->container->get('stripe_bundle.entity_manager')));die; ... }And in the JobRepository class:private function findNextJob(array $excludedJobs = []){ VarDumper::dump('Inside repository'); VarDumper::dump(spl_object_hash($this->getEntityManager()));...Result:"Inside repository""00000000326f44a000000000730f8ec4" "entityManager""00000000326f44b400000000730f8ec4""aws_ses_monitor.entity_manager""00000000326f44b400000000730f8ec4""commands_queues.do_not_use.entity_manager""00000000326f44b400000000730f8ec4""doctrine.orm.default_entity_manager""00000000326f44b400000000730f8ec4""stripe_bundle.entity_manager""00000000326f44b400000000730f8ec4"It's ever the same! This is really unexpected!!! If the EntityManager is ever the same:Why the Job#retryOf object is not already persisted and I have to persist it again to not get the thrown exception?Why the VarDumper gives me two different internal object handles if the object is ever the same? 解决方案 TEST 5. Try to remove all the calls to $this->entityManager->detach()SOLVED! The problem was a detach() that didn't check for the status: if a Job failed I simply detached it to not have it floating around in the EntityManager and as the bundle launches a daemon, I need to free up memory. But I need to free it up only if the Job is definitely failed, while if it has to be retried, I not have to detach it... Or at least I have to reload it if the processing Job refers to it...Damn, building a daemon requires a lot of attention to details! 这篇关于看来我有两个学说实体经理,但我只想要一个! o.O的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
09-22 17:02