2013-08-29 3 views
3

Я хочу кэшировать результаты DB для экземпляра CActiveDataProvider.Yii CActiveDataПоддержка кэширования запросов не работает

Я готовлю поставщика данных в действии контроллера, а затем я использую поставщика данных в CGridView, позже в некотором представлении.

Я использовал этот код:

$cars=new CActiveDataProvider(
    'Car' 
    , 
    array(
     'criteria'=>array(
      'condition'=>'brand_id=:brand_id', 
      'params' => array(':brand_id'=>$model->id), 
      'order' => 'price', 
     ), 
     'pagination'=>false, 
    ) 
);

и, следуя tutorial in the yii wiki, я изменил его:

$cars=new CActiveDataProvider(
     Car::model()->cache(3600) 
     , 
     array(
      'criteria'=>array(
       'condition'=>'brand_id=:brand_id', 
       'params' => array(':brand_id'=>$model->id), 
       'order' => 'price', 
      ), 
      'pagination'=>false, 
     ) 
    );

, но безрезультатно: запрос не кэшируются.

ответ

2

Одним из преимуществ CActiveDataProvider является то, что запрос НЕ выполняется сразу. Запрос выполняется только в том случае, если позднее вы используете CActiveDataProvider, скажем, в CGridView, который вызовет CActiveDataProvider::fetchData, в конечном счете инициируя запрос.

Это полезно, потому что вы можете использовать кеширование фрагментов, и вы не хотите загружать данные в контроллер только для того, чтобы узнать, что он вам не нужен, потому что фрагмент кэшируется.

Это именно то, что происходит здесь: ActiveRecord ->cache() method инструктирует соединение БД кэшировать секвенциальный запрос, но если запрос не выполняется сразу, другой запрос может быть выполнен до этого, и это кэширование не будет работать.

Я решил проблему создания персонализированных ActiveDataProvider, который будет установлен кэш модели непосредственно перед запрос с места:

class CachedActiveDataProvider extends CActiveDataProvider 
{ 

    public $cache_duration = null; 
    public $cache_dependency = null; 

    /** 
    * The cache mechanism works by telling the DB Component to cache the next query. 
    * When fetchData() is called, the DB will cache the next query. 
    * There is a possibility that fetchData call calculateTotalItemCount() 
    * and in that function, if this bit is active, we will tell the DB to cache 
    * 2 queries, the count, and the actual fetch that will come next. 
    * (if we don't do this, the DB will cache the count query, and will forget about 
    * the instruction to cache the fetch query) 
    * 
    * @var boolean 
    */ 
    private $fetching_data = false; 

    protected function fetchData() 
    { 
     if (!is_null($this->cache_duration)) 
     { 
      $this->model->cache($this->cache_duration, $this->cache_dependency); 
     } 

     $this->fetching_data = true; 
     $ret = parent::fetchData(); 
     $this->fetching_data = false; 

     return $ret; 
    } 

    protected function calculateTotalItemCount() 
    { 
     if (!is_null($this->cache_duration)) 
     { 
      $this->model->cache(
       $this->cache_duration, 
       $this->cache_dependency, 
       $this->fetching_data ? 2 : 1 //if fetching data, cache 2 queries: this count and the sequent fetching 
      ); 
     } 

     return parent::calculateTotalItemCount(); 
    } 
}

теперь я могу назвать его помощью

$cars=new CachedActiveDataProvider(
    'Car' 
    , 
    array(
     'criteria'=>array(
      'condition'=>'brand_id=:brand_id', 
      'params' => array(':brand_id'=>$model->id), 
      'order' => 'price', 
     ), 
     'pagination'=>false, 
     'cache_duration' => 3600, 
    ) 
);
Смежные вопросы