onFlush中的预定实体是不同的实例

Xym*_*nek 6 php orm symfony doctrine-orm

\Doctrine\ORM\UnitOfWork::getScheduledEntityDeletions使用内部onFlush事件我有一个奇怪的问题

foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) {
    if ($entity instanceof PollVote) {
        $arr = $entity->getAnswer()->getVotes()->toArray();

        dump($arr);
        dump($entity);

        dump(in_array($entity, $arr, true));
        dump(in_array($entity, $arr));
    }
}
Run Code Online (Sandbox Code Playgroud)

这是结果:

dump()输出

因此,我们看到该对象指向的是与原始实例不同的实例,因此in_array在使用棒比较(AKA ===)时不再产生预期结果.此外,该\DateTime对象指向不同的实例.

我找到的唯一可能的解释是以下(来源):

每当从数据库中获取对象时,Doctrine将保留UnitOfWork内所有属性和关联的副本.因为PHP语言中的变量受"写入时复制"的影响,所以只从数据库中读取对象的PHP请求的内存使用情况与Doctrine不保留此变量副本的内存使用情况相同.只有当你开始更改变量时,PHP才会在内部创建消耗新内存的新变量.

但是,我没有改变任何东西(即使created字段保持原样).在实体上执行的唯一操作是:

  1. \Doctrine\ORM\EntityRepository::findBy (从DB获取)
  2. \Doctrine\Common\Persistence\ObjectManager::remove (安排搬迁)
  3. $em->flush(); (触发与DB的同步)

这让我想到(我可能错了)Doctrine的变更跟踪方法与我遇到的问题无关.这让我想到以下问题:

  • 是什么导致这个?
  • 如何可靠地检查计划删除的实体是否在集合内(\Doctrine\Common\Collections\Collection::contains使用in_array严格比较)或集合中的哪些项目被安排删除?

小智 2

问题是,当您告诉学说删除实体时,它会从身份映射中删除(此处):

<?php

public function scheduleForDelete($entity)
{
    $oid = spl_object_hash($entity);

    // ....

    $this->removeFromIdentityMap($entity);

    // ...

    if ( ! isset($this->entityDeletions[$oid])) {
        $this->entityDeletions[$oid] = $entity;
        $this->entityStates[$oid]    = self::STATE_REMOVED;
    }
}
Run Code Online (Sandbox Code Playgroud)

当你这样做时$entity->getAnswer()->getVotes(),它会执行以下操作:

  1. 从数据库加载所有投票
  2. 对于每一张投票,检查它是否在身份映射中,使用旧的
  3. 如果不在身份映射中,则创建新对象

$entity->getAnswer()->getVotes()尝试在删除实体之前调用。如果问题消失了,那么我是对的。当然,我不会建议将此黑客作为解决方案,只是为了确保我们了解幕后发生的事情。

由于延迟加载, UPD而不是$entity->getAnswer()->getVotes()你应该对所有投票执行 foreach 。如果您只是调用$entity->getAnswer()->getVotes(),Doctrine 可能不会执行任何操作,并且仅当您开始迭代它们时才会加载它们。