A
A
Alexey Pavlov2015-01-11 12:58:05
symfony
Alexey Pavlov, 2015-01-11 12:58:05

How to properly cache data with relationships in Doctrine?

I am using Doctrine ORM in a Symfony2 project and setting up caching of database requests.
I set up result_cache_driver in the doctrine.orm config, and also created separate services for the cache (I use FilesystemCache).
For caching, I use two approaches:
1) the mechanism for caching query results built into the ORM:

$query = $this->em->createQuery('select a from AppBundle:Article a where a.id = :id')
    ->setParameter('id', $id)
    ->useResultCache(true, 0, $cacheKey);
$item = $query->getSingleResult();

2) Separate block caching:
if (($data = $cache->fetch($cacheKey)) === false) {
      $data = doHardWork();
      $cache->save($cacheKey, $data);
}

This approach makes it easy to set up both getting data from the database and caching large calculated data (for example, a list of similar articles found by the tags of the current article). The use of these approaches made it possible to reduce to zero the number of queries to the database when displaying a page. The $cacheKey variable is used so that in the admin panel it would be possible to reset the cache for the edited entity ( here is a good article about it).
The problem occurs when an entity with relationships (ManyToOne or ManyToMany) is used on the page. For example, I have a Video entity with a field associated with the Media entity from the SonataMediaBundle. Doctrine makes a separate query to retrieve data from a related table. To load from the cache, I explicitly ask to make this request in the controller:
$query = $this->em->createQuery('select v from AppBundle:Video v where v.id = :id')
    ->setParameter('id', $id)
    ->useResultCache(true, 0, $cacheKey);
$item = $query->getSingleResult();

$this->em->createQuery('select m from ApplicationSonataMediaBundle:Media m where m.id = :id')
    ->setParameter('id', $item->getVideo()->getId())
    ->useResultCache(true)
    ->getSingleResult();

You do not need to assign the result of this request anywhere, Doctrine will remember it and will not make a second request when requesting a video from a template.
My question is, is it possible to somehow force the Doctrine to load related data in one request?
Specifying fetch="EAGER" in the field annotation doesn't help. $query->setFetchMode doesn't help either. If you receive the necessary data, assign it to the loaded entity object, and save it to a separate cache (in the second caching method above), then some of the bound data from these additional objects is lost for some reason.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey, 2015-01-11
@lexxpavlov

join-s unless explicitly set.
In general, I don’t see the point in your case of using the doctrine query cache if you already have your own caching layer.
ps It's not good to work with QueryBuilder in the controller, but if this case were in the service, then caching would not be a problem.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question