禁用缓存并获取新数据而不分离实体

时间:2016-05-31 00:48:02

标签: caching doctrine-orm

TL; DR:我正在寻找部分或完全禁用Doctrine缓存的方法。

我试图从数据库中获取新数据,首先我不知道Doctrine是否有某种缓存,它是如何工作的,它不会从数据库中获取数据两次。 / p>

(可能比这更复杂,但是我如何理解它以及它如何对我有用,我不在这里解释它是如何工作的,我在这里因为我有问题这种学说的机制。)

例如,让我们说我有代码(我在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"

现在要绕过它我必须使用 $ em-> detach($ user)并且只有在$ sameUser包含从数据库获取的fersh数据之后。我希望 useResultCache useQueryCache ,我试图在构建的查询中将它们设置为false,但它没有帮助。对于单个查询,部分禁用缓存是完美的。

但是,让我们说实体A 引用其中一个实例,例如 userA 的字段指向 userB 由Referer领域。

当我分离 userB 以从数据库中新获取它时,而不是从缓存中获取它,我将得到我想要的但是如果我将尝试在时保存 userA userB 已经脱离,Doctrine会抱怨它不能级联持久引用来自 userB 的引用字段,但是它被分离了,所以Doctrine认为 userA 的引用者是新实体(实际上它是分离的用户B)并使其再次工作,我必须将其设置回来,例如:

$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();    

好的,所以我有解决方法,一切都很好,但有什么我可以做的,所以我得到相同的结果,而不使用分离或刷新实体?我问,因为我发现自己陷入了我无法预测的陷阱。这种陷阱的例子是:

$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.

现在它可能看起来很简单,但我没有预测到,当我将某些付款的用户分离时,我碰巧是推荐用户,它还会从当前登录的用户中分离出来( $ admin )当我脸红时,它试图保存 $ admin $ payment ,但是$ admin实例引用已分离的$ user实例,并认为它是新实例要坚持下去。解决这个问题的一种方法是分离当前登录的用户,或者将 $ user 设置回 $ admin ,就像我使用 $ payment

1 个答案:

答案 0 :(得分:1)

您可以使用$ 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();
}