我在\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));
}
}
结果如下:
因此我们看到该对象指向的是与原始实例不同的实例,因此当使用棒比较(AKA in_array
)时,===
不再产生预期结果。此外,\DateTime
对象指向不同的实例。
我找到的唯一可能的解释是以下(source):
每当从数据库中获取对象时,Doctrine将保留UnitOfWork内所有属性和关联的副本。因为PHP语言中的变量受“写入时复制”的影响,所以只从数据库中读取对象的PHP请求的内存使用情况与Doctrine不保留此变量副本的内存使用情况相同。只有当您开始更改变量时,PHP才会在内部创建新变量,从而消耗新内存。
然而,我没有改变任何东西(即使created
字段保持原样)。在实体上执行的唯一操作是:
\Doctrine\ORM\EntityRepository::findBy
(从DB获取)\Doctrine\Common\Persistence\ObjectManager::remove
(安排删除)$em->flush();
(触发与DB的同步)这让我想到(我可能错了),该学说的变化跟踪方法与我遇到的问题无关。这让我想到了以下问题:
\Doctrine\Common\Collections\Collection::contains
使用in_array
进行严格比较)或者集合中的哪些项目计划删除?答案 0 :(得分:1)
问题在于,当您告诉doctrine删除实体时,它将从身份地图(here)中删除:
<?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;
}
}
当你执行$entity->getAnswer()->getVotes()
时,它会执行以下操作:
尝试在删除实体之前调用$entity->getAnswer()->getVotes()
。如果问题消失,那我就是对的。当然,我不建议将此黑客作为解决方案,只是为了确保我们了解幕后发生的事情。
UPD 而不是$entity->getAnswer()->getVotes()
你应该为所有选票做foreach,因为延迟加载。如果你只是调用$entity->getAnswer()->getVotes()
,Doctrine可能不会做任何事情,只有当你开始迭代它们时才会加载它们。
答案 1 :(得分:0)
来自doc:
如果您调用EntityManager并要求具有特定ID两次的实体,它将返回相同的实例
所以调用两次findOneBy(['id' => 12])
应该会产生两个完全相同的实例。
所以这一切都取决于Doctrine如何检索这两个实例。
在我看来,你在$ arr中得到的是来自Answer实体中$ votes的一对多关联,这导致ORM单独查询(可能是id IN (12)
)。
您可以尝试的是将此关联声明为EAGER(fetch="EAGER"
),它可能会强制ORM进行特定查询并将其保留在缓存中,以便第二次获取它时,相同实例返回?
您可以查看日志并在此处发布吗?它可能表示一些有趣或至少与进一步调查相关的内容。