Использую Doctrine ORM в проекте на Symfony2, и настраиваю кэширование запросов к БД.
Настроил result_cache_driver в конфиге doctrine.orm, а также создал отдельные сервисы для кэша (использую FilesystemCache).
Для кэширования использую два подхода:
1) встроенный в 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) Отдельное кэширование блоков:
if (($data = $cache->fetch($cacheKey)) === false) {
$data = doHardWork();
$cache->save($cacheKey, $data);
}
Такой подход позволяет легко настроить и получение данных из БД, и кэшировать большие вычисляемые данные (например, список похожих статей, найденных по тегам текущей статьи). Использование этих подходов позволило уменьшить до нуля кол-во запросов к БД при показе страницы. Переменная $cacheKey используется для того, чтобы в админке можно было бы сбросить кэш для редактируемой сущности (
вот тут есть хорошая статья про это).
Проблема возникает в тот момент, когда на странице используется сущность со связями (ManyToOne или ManyToMany). Например, у меня есть сущность Video с полем, связанным с сущностью Media из SonataMediaBundle. Для получения данных из связанной таблицы доктрина делает отдельный запрос. Для загрузки из кэша я явно запрашиваю сделать этот запрос в контроллере:
$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();
Никуда присваивать результат этого запроса не требуется, Доктрина запомнит его и при запросе к видео из шаблона уже не будет делать повторный запрос.
Вопрос мой в том, можно ли как-то заставить Доктрину загружать связанные данные одним запросом?
Указывание fetch="EAGER" в аннотации поля не помогает. $query->setFetchMode тоже не помогает. Если получать нужные данные, присваивать их в загруженный объект сущности, и сохранять в отдельный кэш (во втором способе кэширования выше), то часть привязанных данных из этих дополнительных объектов почему-то теряется.