如何在Symfony 2.4中使用缓存ID和缓存生命周期选项缓存doctrine的"findOneBy()"查询?

15

我正在使用Doctrine 2.4和Symfony 2.5项目,希望通过缓存ID和缓存时间来缓存查询结果,以便在需要时可以通过管理员删除缓存结果。我已经成功使用"createQueryBuilder()"选项进行了查询结果缓存。以下是一个示例:

Example:

$this->createQueryBuilder('some_table')
                    ->select('some_table')
                    ->where('some_table.deleted_date IS NULL')
                    ->getQuery()
                    ->useResultCache(true)
                    ->setResultCacheLifetime(120) //Query Cache lifetime
                    ->setResultCacheId($queryCacheId) //Query Cache Id
                    ->getResult();

但我无法找到与“findOneBy()”选项缓存查询结果的类似方式。

示例:

$this->findOneBy(array('some_field'=>$some_value));

我正在寻找一些适当的解决方案,任何帮助都非常感激。


1
正如Ocramius所说,如果你想利用缓存操作,你需要在repo中覆盖这个方法。 - DonCallisto
谢谢您的回复。让我试一下,如果需要的话会再问您。 - Yogesh Salvi
这是我如何在存储库类中覆盖“findOneBy”函数的方法:public function findOneBy(array $criteria_array) { $query = $this->createQueryBuilder('b')->select('b'); foreach($criteria_array as $fieldName=>$criteria) { $query->andWhere("b.$fieldName = :$fieldName"); $query->setParameter("$fieldName", $criteria); } return $query->getQuery() ->useResultCache(true) ->setResultCacheLifetime(120) ->setResultCacheId($queryCacheId) ->getResult(); }请检查并更正我的错误。
当我需要缓存结果时,我是否需要在所有存储库中覆盖“find *”函数?
- Yogesh Salvi
1
是的,您需要覆盖您需要的每个函数。我相信Ocramius的答案,因为他是Doctrine2的开发人员之一 ;) - DonCallisto
明白了,感谢你的帮助 :) - Yogesh Salvi
你能把你的观点写成答案吗?这样我就可以接受它了。 - Yogesh Salvi
3个回答

6

2
创建一个通用函数来实现这个功能。
 $repo->findOneByYourSufff($yourStuff, $yourRepoClass);

紧随你常见的功能之后:

 public function findOneByYourSufff($yourStuff, $yourRepoClass) {


         $q = $this->createQueryBuilder()
                ->select('x.*')
                ->from($yourRepoClass, 'x');

                foreach($yourStuff as $fieldKey => $wh) {
                    $q->andWhere("b.$fieldKey = :fieldName");
                    $q->setParameter("fieldName", $wh);
                }

          $q->useResultCache(true)
                ->setResultCacheLifetime(120) //Query Cache lifetime
                ->setResultCacheId($queryCacheId) //Query Cache Id
                ->getSingleResult();

    return $q

 }

这不是一个解决方案:$yourStuff 可能是一个数组,你如何处理这种情况? - DonCallisto
你可以将 ->where('x.yourStuff = ?', $yourStuff) 放在循环中。 在逻辑函数中准备好你的数组。 - Suf_Malek
首先,这并不是那么“容易”(你应该在循环中使用 andWhere()),其次,你的回答没有强调这一点,对我来说不是一个好的回答。请更新它。 - DonCallisto
不是的,似乎不是这样。andWhere() 是什么?我的意思是,在 where() 调用之后,在循环函数中使用这个 andWhere() - DonCallisto
Sufiyan Malek,你的方法也帮助我找到了最终的解决方案。同样感谢你。 - Yogesh Salvi
@DonCallisto:即使您第一次使用andWhere(),也可以使用它,无需先使用where()函数。 - Radium

1
这里是一个示例,演示如何缓存单个仓库的函数结果:
  • findOneBy(['foo' => 'bar'])
  • findOneByFoo('bar')
  • findOneBy(['bar' => 'foo', 'foo' => 'bar')
  • 等等...
它覆盖了EntityRepository::FindOneBy函数。它遵循相同的签名,因此无需更新调用代码。所有FindOneBy%类型的调用都将通过我们的findOneBy实现。
<?php
/**
* MyObject Repo    
*/

namespace MyLib\Entity\Repository;
use Doctrine\ORM\EntityRepository;

class MyObjectRepository extends EntityRepository
{

    const CACHE_KEY = 'my_object';
    const ALIAS = 'my_object';

    /**
     * Override - use cache.
     *
     * @param array $criteria
     * @param array|null $orderBy
     * @return mixed
     */
    public function findOneBy(array $criteria, array $orderBy = null)
    {
        $queryBuilder = $this->createQueryBuilder(self::ALIAS);
        foreach($criteria as $field => $value) {
            $queryBuilder->andWhere(self::ALIAS . ".{$field} = :{$field}")->setParameter($field, $value);
        }
        if (is_array($orderBy)) {
            foreach ($orderBy as $field => $dir) {
                $queryBuilder->addOrderBy($field, $dir);
            }
        }
        $queryBuilder->setMaxResults(1);

        $query = $queryBuilder->getQuery();

        $query->useResultCache(true, 3600, self::CACHE_KEY);

        $result = $query->getResult();

        if ($result) return reset($result);

        return $result;
    }

    /**
     * Depending how you hydrate the entities may make more 
     * sense to use cache layer at findAll
     *
     * @param void
     * @return array The entities.
     */
    public function findAll()
    {
        $query = $this->getEntityManager()->createQuery('select v from \OAS\Entity\MyObject v');

        $query->useResultCache(true, 3600, self::CACHE_KEY);

        $result = $query->getResult();

        return $result;
    }

    /**
     *
     */
    public function invalidateCache()
    {
        //this would depend on your cache implementation...
        $container = \Zend_Registry::get('doctrine');

        $cache = $container->getCacheInstance();

        $cache->delete(self::CACHE_KEY);
    }
}

当然,这可以更加面向对象地完成,通过扩展一个中介类来实现,如果你想在仓库上拥有一个属性,它可以简单地开启或关闭缓存。你可以对其他仓库操作函数采用类似的方法进行扩展。

错误的实现。你将为所有查询使用一个缓存。findOneBy(['name' => 'foo'], ['name' => 'asc']) === findOneBy(['title' => 'foo'], ['title' => 'desc']) === findAll() - ghost404
如果我理解你的意思是错误的,@ghost404。Doctrine二级缓存知道查询的情况。在抽象中看到从查询对象哈希派生的$querykey。我相当确定至少有这样的代码在我的生产环境中运行了好几年。 - ficuscr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接