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 になっています。また、結果キャッシュが登場するのはこれが初めてです。
結果キャッシュがエンティティを切り離す方法/理由は?