【问题标题】:How to cache doctrine "findOneBy()" query with cache id and cache lifetime option in Symfony 2.4?如何在 Symfony 2.4 中使用缓存 ID 和缓存生命周期选项缓存学说“findOneBy()”查询?
【发布时间】:2015-04-24 10:34:42
【问题描述】:

我正在使用学说 2.4 进行 symfony 2.5 项目。

我想用缓存 id 和缓存时间来缓存查询结果,所以我可以在需要时通过管理员删除缓存结果。

我可以使用“createQueryBuilder()”选项缓存查询结果。

例子:

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

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

【问题讨论】:

  • groups.google.com/d/msg/doctrine-user/RIeH8ZkKyEY/HnR7h2p0lCQJ 正如 Ocramius 所说,如果您想利用缓存操作,您需要将此方法覆盖到 repo 中。
  • 感谢您的回复。让我试试看,如果需要,我会问你更多。
  • 这就是我如何覆盖存储库类中的“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);返回 $query->getQuery() ->useResultCache(true) ->setResultCacheLifetime(120) ->setResultCacheId($queryCacheId) ->getResult(); } 请检查并纠正我。每当我需要缓存结果时,是否需要覆盖所有存储库中的“find*”功能?
  • 是的,你需要覆盖你需要的每一个函数。我相信 Ocramius 的回答,因为他是 Doctrine2 开发者之一;)
  • 明白你的意思。感谢您的帮助:)

标签: php symfony caching doctrine-orm


【解决方案1】:

您需要将每个 findBy* 或 findOneBy* 函数重新定义到自定义存储库中:这是唯一的方法,因为教义 2 默认行为不考虑这种情况。 很遗憾,这取决于你。

Ocramius(Doctrine2 开发者)也在这里说 https://groups.google.com/d/msg/doctrine-user/RIeH8ZkKyEY/HnR7h2p0lCQJ

【讨论】:

    【解决方案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 可能是一个数组,你如何处理这种情况?
    • 您可以将 ->where('x.yourStuff = ?', $yourStuff) 放入循环中。在你的逻辑函数中准备你的数组。
    • 首先,不是那么“简单”(你应该使用andWhere() [在你的循环中]),其次你的回答没有强调这一点,所以对我来说,这不是一个好的答案。请更新它
    • 不,似乎没有。 andWhere() 是什么?我的意思是,在调用where() 之后,您应该在循环函数中使用这个andWhere()
    • Sufiyan Malek,你的方式也帮助我找到了最终的解决方案。也谢谢你。
    【解决方案3】:

    这是一个示例,说明如何从单个存储库中为函数缓存结果:

    • 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);
        }
    }
    

    如果您想说在存储库上有一个简单地打开或关闭缓存的属性,这当然可以以更 OOP 的方式完成,扩展一个中间类。您可以为其他存储库操作功能扩展类似的方法。

    【讨论】:

    • 执行不正确。您将拥有一个用于所有查询的缓存。 findOneBy(['name' =&gt; 'foo'], ['name' =&gt; 'asc']) === findOneBy(['title' =&gt; 'foo'], ['title' =&gt; 'desc']) === findAll()
    • @ghost404 如果我明白你在说什么,那你就错了。 Doctrine 二级缓存具有查询意识。请参阅$querykey 派生自摘要中查询对象的哈希。至少可以肯定。多年来,我的代码在生产中都在做类似的事情。
    猜你喜欢
    • 2021-01-30
    • 2012-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-29
    • 1970-01-01
    • 2014-06-25
    • 1970-01-01
    相关资源
    最近更新 更多