CActiveDataProvider 的优点之一是不会立即执行查询。仅当您稍后使用 CActiveDataProvider 时才会执行查询,例如在 CGridView 中,这将调用CActiveDataProvider::fetchData
最终触发查询。
这很有用,因为您可以使用片段缓存,并且您不想在控制器中加载数据只是发现您不需要它,因为片段已缓存。
这正是这里发生的情况:ActiveRecord->cache()
方法指示 DB Connection 缓存后续查询,但如果查询没有立即执行,则可以在此之前执行一些其他查询,并且这种缓存将不起作用。
我解决了创建个性化 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,
)
);