Symfony 为什么我的学说习惯寄托认为,我的实体是分离的?

Symfony 为什么我的学说习惯寄托认为,我的实体是分离的?,symfony,doctrine-orm,Symfony,Doctrine Orm,我的自定义Doctrine2存储库有一个奇怪的问题 我有一个删除控制器,基本上如下所示: public function deleteAction(MyEntity $myEntity, MyEntityRepository $myEntityRepository) { $myEntityRepository->remove($myEntity); $myEntityRepository->flushEntityManager(); return new J

我的自定义Doctrine2存储库有一个奇怪的问题

我有一个删除控制器,基本上如下所示:

public function deleteAction(MyEntity $myEntity, MyEntityRepository $myEntityRepository)
{
    $myEntityRepository->remove($myEntity);
    $myEntityRepository->flushEntityManager();

    return new JsonResponse(['message' => 'Bye bye!']);
}
public function remove(MyEntity $entity): MyEntityRepository
{
    $this->getEntityManager()->remove($entity);
    return $this;
}
存储库的删除方法如下所示:

public function deleteAction(MyEntity $myEntity, MyEntityRepository $myEntityRepository)
{
    $myEntityRepository->remove($myEntity);
    $myEntityRepository->flushEntityManager();

    return new JsonResponse(['message' => 'Bye bye!']);
}
public function remove(MyEntity $entity): MyEntityRepository
{
    $this->getEntityManager()->remove($entity);
    return $this;
}
这以前是有效的,但现在,我有一个例外:

分离实体AppBundle\entity\MyEntity@000000003b458c32000000007fd2994a无法删除

我真的不知道,为什么存储库中的EntityManager认为实体是分离的。当我将EntityManager直接注入控制器时,一切正常:

public function deleteAction(MyEntity $myEntity, EntityManagerInterface $em)
{
    $em->remove($myEntity);
    $em->flush();

    return new JsonResponse(['message' => 'Bye bye!']);
}
有什么想法吗?为什么从条令\ORM\EntityRepository->getEntityManager()获得的EntityManager与注入控制器的不同

另外,我的其他删除操作没有这个问题,它们都使用相同的自定义存储库。这让我发疯

编辑:在存储库中转储
$this->getEntityManager()
会产生:

EntityManager {#627 ▼
-config: Configuration {#461 ▶}
-conn: Connection {#471 ▶}
-metadataFactory: ClassMetadataFactory {#618 ▶}
-unitOfWork: UnitOfWork {#493 ▶}
-eventManager: ContainerAwareEventManager {#511 ▶}
-proxyFactory: ProxyFactory {#588 ▶}
-repositoryFactory: DefaultRepositoryFactory {#619 ▶}
-expressionBuilder: null
-closed: false
-filterCollection: FilterCollection {#598 ▶}
-cache: null
}
在控制器中转储
$em

DoctrineORMEntityManager_00000000644c03b80000000000dac8cc6811571fd60520ff7ea135d840b51abe {#410 ▼
-valueHolder59cfe1676bb7b138763071: EntityManager {#664 …11}
-initializer59cfe1676bb84613288121: null
}

我创建了一个新的空Symfony项目来一步一步地重现这个问题。当我实现我的实体侦听器时,我遇到了同样的错误,它有一个助手类作为依赖项,它本身也有MyEntityRepository作为依赖项。删除此依赖项可消除分离实体的问题

后来,我意识到,注入的EntityManager实例有时是新实例。要注入主实例(顺便说一下,要删除循环引用错误),可以将实体侦听器服务标记为惰性:

AppBundle\EventListener\MyEntityListener:
    autowire: true
    autoconfigure: true
    # the service must be public, when it's tagged lazy
    public: true
    tags:
        - { name: doctrine.orm.entity_listener, lazy: true }
这个懒惰的东西解决了我的问题

但我仍然不明白,当另一个服务注入了EntityManager的存储库时,为什么我会将EntityManager的另一个实例注入到我的存储库中

作为记录,MyEntityRepository配置:

AppBundle\Entity\Repository\MyEntityRepository:
    autowire: false
    autoconfigure: true
    public: false
    factory: ['@doctrine.orm.default_entity_manager', getRepository]
    arguments:
        - AppBundle\Entity\MyEntity
侦听器服务:

class MyEntityListener
{
    /** @var MyEntityHelper */
    protected $myEntityHelper;

    public function __construct(MyEntityHelper $myEntityHelper)
    {
        $this->myEntityHelper = $myEntityHelper;
    }
    // ...
}
class MyEntityHelper
{
    /** @var MyEntityRepository */
    protected $myEntityRepository;

    // this injection of MyEntityRepository creates the problem
    // with the two instances of the EntityManager
    // unless the MyEntityListener is tagged as lazy
    public function __construct(MyEntityRepository $myEntityRepository)
    {
        $this->myEntityRepository = $myEntityRepository;
    }
    // ...
}
及助手服务:

class MyEntityListener
{
    /** @var MyEntityHelper */
    protected $myEntityHelper;

    public function __construct(MyEntityHelper $myEntityHelper)
    {
        $this->myEntityHelper = $myEntityHelper;
    }
    // ...
}
class MyEntityHelper
{
    /** @var MyEntityRepository */
    protected $myEntityRepository;

    // this injection of MyEntityRepository creates the problem
    // with the two instances of the EntityManager
    // unless the MyEntityListener is tagged as lazy
    public function __construct(MyEntityRepository $myEntityRepository)
    {
        $this->myEntityRepository = $myEntityRepository;
    }
    // ...
}

在尝试删除该实体之前,该实体会发生什么情况?获取symfony debugger面板的帮助,并在数据库部分查看doctrine生成的查询列表,如果存在回滚,则手动尝试执行这些查询以查看实际错误可能是其生成某种与db相关的错误只有一个实体管理器?使用ParamConverter注入实体?@svgrafovn除此之外,该控制器就是全部,该请求中发生了什么@Cerad只有一个EntityManager,是的,该实体通过ParamConverter注入。@MKhalidJunaid我将查看查询,但我不希望在那里找到什么。这个最小的控制器实际上并没有做任何其他的事情。怪异似乎是一个准确的描述。这次行动有没有可能被要求两次?使用任何不寻常的条令相关包?手动清除缓存并牺牲一只山羊可能会有所帮助。听起来好像共享服务属性设置为false,但我不知道如何设置。另外,将实体管理器注入实体侦听器通常会触发循环依赖项异常。在大多数情况下,您只想从事件中提取实体管理器。我改变了这一点:以前,这是一个
原则。事件侦听器
,我从事件中提取了实体管理器。但是现在,逻辑被外包给助手服务,注入EntityManager,监听器被更改为
条令.orm.entity_监听器
,其中方法接收实体而不是事件,并使用助手来完成工作。我在条令的文档中没有看到这个警告标志:“实体侦听器可以是任何类,默认情况下它应该是一个具有无参数构造函数的类。”那么,这样的侦听器应该如何利用服务呢?这本身并不是条令的限制。相反,它是Symfony容器创建实体管理器和添加侦听器的方式。由于容器本身不了解原则,因此通过使用setter依赖项注入来添加侦听器。这是个巧妙的把戏。查看缓存目录中生成的容器代码以了解它们是如何组合在一起的是很有启发性的。尽管如此,我自己的经验是,条令实体侦听器对其功能有很多限制。每当我试图从监听器内部使用实体管理器时,我就会遇到这样或那样的障碍。在任何情况下(我猜是双关语),你都可以调整你的助手函数,将实体管理器和实体作为输入。谢谢你的解释,这对理解发生了什么有很大帮助。我没有预料到这样的副作用,因为助手服务和侦听器都与EntityManager无关,因为所有数据库内容都封装在存储库中,存储库被注入到我的控制器和助手服务中,默认情况下可以访问EntityManager。我最近对代码进行了重构,以消除几乎所有EntityManager依赖项,将所有数据库工作转移到存储库中。我认为那是个好主意/