如何强制原则从数据库重新加载数据?

问题描述 投票:0回答:8

我在 symfony2.1 安装中使用doctrine/mongodb 1.0.0-BETA1。

所以我试图强制我的存储库从数据库调用数据,而不是使用它已缓存的对象。

$audit = $dm->getRepository("WGenSimschoolsBundle:Audit")->findOneById("xxxx");

.... do something somewhere to change the object ....

此时如果我打电话

$audit = $dm->getRepository("WGenSimschoolsBundle:Audit")->findOneById("xxxx");

审核数据未发生变化。它仍然拥有最初获取的对象。如果我尝试

$dm->refresh($audit) 

我也得到同样的结果。我是否可以返回数据库获取该值?

symfony-2.1 doctrine-odm
8个回答
64
投票

您是否刷新了对

$audit
对象的更改?

$audit = $dm->getRepository("WGenSimschoolsBundle:Audit")->findOneById("xxxx");
//do something somewhere to change the object
$dm->flush();

每次执行

findBy(...)
findOneBy(...)
时,它实际上都会从数据库中获取新文档。 (您应该在 Symfony 分析器中看到查询)

使用 find() 代替,它将从其内部代理缓存中获取文档。 文档将保留在代理缓存中,直到您调用

$dm->clear()
方法。


46
投票

这对我有用:

$doc = $this->documentManager->getRepository('MyBundle:MyDoc')->find($id);

/* ... in the meanwhile another external process is doing some changes to the object ...*/
$doc = $this->documentManager->getRepository('MyBundle:MyDoc')->find($id); // Perhaps this is not useful
$this->documentManager->refresh($doc);

29
投票

添加到前面的答案中,我正在搜索如何刷新

Entity
的数据库,而不是
Document
的数据库,但解决方案很接近。我将其发布在这里是为了其他遇到同样问题的人。

在我的一项功能测试中,我使用了两次相同的查询:

$em = $kernel->getContainer()->get('doctrine.orm.entity_manager');
$user = $em->getRepository('AcmeUserBundle:User')->findOneBy(array('email' => '[email protected]'));
echo "Old hash: ".$user->getPassword() . "\n";
// result: 8bb6118f8fd6935ad0876a3be34a717d32708ffd

然后测试会经历一个更改密码的过程。然后,我重新查询用户,以比较密码哈希是否已与 same 查询发生更改:

$user = $em->getRepository('AcmeUserBundle:User')->findOneBy(array('email' => '[email protected]'));
echo "New hash: ".$user->getPassword() . "\n";
// result: 8bb6118f8fd6935ad0876a3be34a717d32708ffd # Same !

问题是,即使测试的控制器更新了哈希值,实体管理器仍将实体保存在cache中。

因此,解决方案是在两个查询之间添加以下内容:

$em->clear();

现在,密码哈希在查询之间发生了变化!耶!


9
投票

您可以使用方法刷新:

$post; # modified
$entityManager->refresh();
$post; # reset from db

3
投票

在处理相关实体时,如果修改了相关实体并通过父对象保存,则必须添加选项cascade={"detach"}才能使分离生效。

例如,假设您想要更新 Person 对象上的朋友列表,方法是向列表中添加新对象、删除其中一些对象并更新一些现有对象。你将会拥有

$em->flush();
$em->detach($entity);

并在您的 Person 实体中确保更新您的朋友关系:

@ORM\OneToMany(targetEntity="Somewhere\PeopleBundle\Entity\Person", mappedBy="person", cascade={"detach"})
private $friends;

1
投票

尝试类似的事情

$dm->getUnitOfWork()->clear('WGenSimschoolsBundle:Audit');

0
投票

您需要使用

EntityManager#clear()
。请参阅文档


0
投票

大型数据集可能需要额外考虑:

  • \Doctrine\ORM\EntityManager::refresh()
    一次仅接受一个对象,因此您可以通过连续相同的
    SELECT ... WHERE id = ?
    往返来淹没数据库。
  • \Doctrine\ORM\EntityRepository::findBy()
    不是一个选项,因为如果实体已经持久化,水合会完全忽略结果集。
  • \Doctrine\ORM\EntityManager::detach()
    可能不是一个选项,因为您需要事后持久化以避免非持久化实体错误,这样做还可能触发 通过关系找到新实体错误,具体取决于实体关系的复杂性。

一种可能的替代方法是创建一个存储库方法,该方法组成 DQL 查询并启用

Query::HINT_REFRESH
提示。在水合过程中使用提示(参见
\Doctrine\ORM\UnitOfWork::createEntity()
)来丢弃缓存的数据。

public function refreshByIds(array $ids): array
{
    return $this->createQueryBuilder('entity')
        ->where('entity.id in (:ids)')
        ->setParameter('ids', $ids)
        ->getQuery()
        ->setHint(Query::HINT_REFRESH, true)
        ->getResult();
}
© www.soinside.com 2019 - 2024. All rights reserved.