我在 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)
我也得到同样的结果。我是否可以返回数据库获取该值?
您是否刷新了对
$audit
对象的更改?
$audit = $dm->getRepository("WGenSimschoolsBundle:Audit")->findOneById("xxxx");
//do something somewhere to change the object
$dm->flush();
每次执行
findBy(...)
或 findOneBy(...)
时,它实际上都会从数据库中获取新文档。 (您应该在 Symfony 分析器中看到查询)
使用 find() 代替,它将从其内部代理缓存中获取文档。 文档将保留在代理缓存中,直到您调用
$dm->clear()
方法。
这对我有用:
$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);
添加到前面的答案中,我正在搜索如何刷新
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();
现在,密码哈希在查询之间发生了变化!耶!
您可以使用方法刷新:
$post; # modified
$entityManager->refresh();
$post; # reset from db
在处理相关实体时,如果修改了相关实体并通过父对象保存,则必须添加选项cascade={"detach"}才能使分离生效。
例如,假设您想要更新 Person 对象上的朋友列表,方法是向列表中添加新对象、删除其中一些对象并更新一些现有对象。你将会拥有
$em->flush();
$em->detach($entity);
并在您的 Person 实体中确保更新您的朋友关系:
@ORM\OneToMany(targetEntity="Somewhere\PeopleBundle\Entity\Person", mappedBy="person", cascade={"detach"})
private $friends;
尝试类似的事情
$dm->getUnitOfWork()->clear('WGenSimschoolsBundle:Audit');
大型数据集可能需要额外考虑:
\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();
}