我在使用 Doctrine ORM 的结果缓存时遇到了问题。该应用程序通过 JSON REST 接口管理创建/删除通道实体并将数据添加到通道以进行监控。出于性能原因,需要跨请求缓存通道实体,因为它们大多是静态的。
在单元测试期间,我们发现流程存在问题 1) 创建通道 2) 添加数据和 3) 删除通道。下面的代码中使用了一个新的实体管理器来模拟单独的 JSON 请求以进行测试:
public function run() {
// 1) add channel
$this->em = self::createEntityManager();
$channel = new Model\Channel('power');
echo($uuid = $channel->getUuid());
$this->setProperties($channel, array('title'=>'Meter', 'resolution'=>100));
$this->em->persist($channel);
$this->em->flush();
$this->clearCache();
// 2) add data
$this->em = self::createEntityManager();
$channel = $this->get($uuid);
$this->dumpEntityState($channel, 'add ');
$channel->addData(new Model\Data($channel, 1000000, 1));
$this->em->flush();
$this->dumpEntityState($channel, 'adddata ');
// this fixes the problem
// $this->clearCache();
// 3) delete channel
$this->em = self::createEntityManager();
$entity = $this->get($uuid);
$this->dumpEntityState($channel, 'delete ');
if ($entity instanceof Model\Channel) {
$entity->clearData($this->em);
}
$this->em->remove($entity);
$this->em->flush();
$this->clearCache();
}
通道实体通过其标识符检索:
public function get($uuid) {
if (!Util\UUID::validate($uuid)) {
throw new \Exception('Invalid UUID: \'' . $uuid . '\'');
}
$dql = 'SELECT a, p
FROM Volkszaehler\Model\Entity a
LEFT JOIN a.properties p
WHERE a.uuid = :uuid';
$q = $this->em->createQuery($dql);
$q->setParameter('uuid', $uuid);
// this breaks the app
$q->useResultCache(true);
try {
return $q->getSingleResult();
} catch (\Doctrine\ORM\NoResultException $e) {
throw new \Exception('No entity found with UUID: \'' . $uuid . '\'', 404);
}
}
现在的问题是,一旦useResultCache(true)
使用,在步骤 3)中删除实体会导致错误:
Uncaught exception 'InvalidArgumentException' with message 'A detached entity can not be removed.' in \ORM\UnitOfWork.php
只要useResultCache()
是false
,问题就消失了。
resultCache 如何影响实体的删除,尤其是在更新通道实体时清除结果缓存时?
更新
在从现有实体管理器中添加新检索到的实体上的数据后检查通道实体状态,它的状态已经 DETACHED。这也是结果缓存第一次发挥作用。
结果缓存如何/为什么使实体分离?