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

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 数据之后。我对useResultCacheuseQueryCache抱有希望,我尝试在构建的查询上将它们设置为 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所做的那样。

d.g*_*zha 5

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