如何在Symfony 2中阻止Doctrine 2缓存结果?

34

我希望能够检索实体的现有版本,以便我可以将其与最新版本进行比较。例如,编辑文件时,我想知道该值是否自从在数据库中以来已经更改。

    $entityManager = $this->get('doctrine')->getEntityManager();
    $postManager = $this->get('synth_knowledge_share.manager');

    $repository = $entityManager->getRepository('KnowledgeShareBundle:Post');
    $post = $repository->findOneById(1); 

    var_dump($post->getTitle()); // This would output "My Title"
    $post->setTitle("Unpersisted new title");

    $existingPost = $repository->findOneById(1); // Retrieve the old entity

    var_dump($existingPost->getTitle()); // This would output "Unpersisted new title" instead of the expected "My Title"

有人知道我怎样才能避开这个缓存吗?

2个回答

50

这是正常的行为。

Doctrine在EntityManager中存储检索到的实体的引用,因此可以通过其id返回实体而无需执行其他查询。

你可以像这样做:

$entityManager = $this->get('doctrine')->getEntityManager();
$repository = $entityManager->getRepository('KnowledgeShareBundle:Post');
$post = $repository->find(1);

$entityManager->detach($post);

// as the previously loaded post was detached, it loads a new one
$existingPost = $repository->find(1);

但是请注意,由于$post实体已经分离,如果你想要再次持久化它,你必须使用->merge()方法。


4
美味,这个“detach”非常完美。 - Elliot Coad
13
谢谢。小提示:如果您需要分离所有实体(例如在非隔离测试中),可以使用 $entityManager->clear() - richsage
另一个需要注意的是你是否有一个事务处于打开状态。如果你已经执行了 $entityManager->beginTransaction(),请确保在尝试清除实体管理器之前关闭事务(例如 $entityManager->rollback())。一个未关闭的事务将强制使用一致的、因此未更新的数据库视图。 - stanhope
对于大多数情况,对于大多数人,大部分时间内,refresh()(参见Battle Mage的答案)可能是更自然的解决方案。 - Jeffiekins

23

您还可以使用refresh方法,该方法可从数据库中刷新实体的持久状态,覆盖任何尚未持久化的本地更改。

$entityManager = $this->get('doctrine')->getEntityManager();
$repository = $entityManager->getRepository('KnowledgeShareBundle:Post');
$post = $repository->find(1);

$entityManager->refresh($post);

现在,$post 变量包含了来自数据库的最新版本。


1
您真是个救命恩人! - Joseph Astrahan
这真的很有用,似乎鲜为人知。值得注意的是,在相关实体上设置cascade="REFRESH"以使其正常工作。 - DevDonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接