Mr_*_*oKa 2 caching doctrine-orm
TL;DR:我正在寻找部分或完全禁用 Doctrine 缓存的方法。
我试图从数据库中获取新数据,首先我不知道 Doctrine 是否有某种缓存,它是如何工作的,它不会从数据库中获取数据两次。
(它可能比这更复杂,但是我如何理解它以及它如何对我起作用,我不是在这里解释它是如何工作的,我来这里是因为我对这种学说机制有疑问。)
例如,假设我有代码(我在 Symfony 下工作):
$em = $this->getDoctrine()->getManager();
$repo = $this-getRepository('AppBundle:User');
$user = $repo->getUserById(1);
echo $user->getName(); // It will print "User"
sleep(5); // I give myself some time to change user name to anything else than "User"
$sameUser = $repo->getUserById(1);
echo $sameUser->getName(); // It still prints out "User"
Run Code Online (Sandbox Code Playgroud)
现在要解决这个问题,我必须使用$em->detach($user)并且只有在 $sameUser 包含从数据库获取的 fersh 数据之后。我对useResultCache和useQueryCache抱有希望,我尝试在构建的查询上将它们设置为 false,但这没有帮助。部分禁用单个查询的缓存将是完美的。
但假设我有实体 A引用其实例之一,因此例如userA具有通过 Referer 字段指向userB 的字段。
当我分离userB以从数据库而不是从缓存中新鲜获取它时,我会得到我想要的东西,但是如果我在分离userB时尝试保存userA ,Doctrine 会抱怨它无法级联保留userB所在的引用字段,但是它已分离,因此 Doctrine 认为userA的引荐来源网址是新实体(实际上它是分离的 userB),为了使其再次工作,我必须将其设置回来,例如:
$userA = $repo->getUserById(1);
$userB = $userA->getReferrer();
$em->detach($userB);
$userBAgain = $repo->getUserById($userB->getId());
$userA->setRferrer($userBAgain); //Without this doctrine thinks that userA has new entity that haven't been persisted yet.
$em->flush();
Run Code Online (Sandbox Code Playgroud)
好的,所以我有解决方法,一切都很好,但是我可以做些什么,以便在不使用实体上的分离或刷新的情况下获得相同的结果?我问这个问题是因为我不断发现自己陷入了我没有预料到的陷阱中。这种陷阱的例子是:
$admin = $this->getUser(); //is current logged user
// it always exists there even if I don't use **getUser** method.
// This currently logged user is an admin, and it is Referrer of $user
$user = $payment->getUser(); //User, currently logged admin is referrer.
$em->detach($user); // Detached
$user = $repo->getUserById($user->getId()); //Fetch fresh data.
$payment->setUser($user); // Set it back so...
$em->flush() // ...So Doctrine won't complain about it when you save payment.
Run Code Online (Sandbox Code Playgroud)
现在看起来可能很容易,但我没有预料到,当我分离我碰巧是推荐人的某些付款的用户时,它也与当前登录的用户($admin)分离,当我刷新时,它试图保存$admin和$ payment,但 $ admin 实例引用了已分离的 $ user 实例,并且它认为它是要持久保存的新实例。解决这个问题的一种方法是分离当前登录的用户,或者将$user也设置回$admin,就像我对$ payment所做的那样。
您可以使用 $entityManager->refresh($entity) 更新单个实体
从数据库刷新实体的持久状态,覆盖尚未持久的任何本地更改。
或者在 DQL 查询中使用Query::HINT_REFRESH :
public function getUserById()
{
return $this->em->createQuery('SELECT u, g FROM MyBundle:User u LEFT JOIN u.groups g WHERE u.id = 3')
->setHint(Query::HINT_REFRESH, true)
->getResult();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2759 次 |
| 最近记录: |