CDbCacheDependency subsequvent calls

If i have two methods in a Post model, like




public static function a(){

  

 $dependency=new CDbCacheDependency('SELECT AVG(UNIX_TIMESTAMP(last_updated)) FROM {{post}}');

 $criteria=new CDbCriteria;

 $criteria->select='post_id,title';

 $criteria->order='post_id DESC';

 $models=self::model()->cache(1000,$dependency)->findAll($criteria);

 return $models;

            

}


public static function b(){

  

 $dependency=new CDbCacheDependency('SELECT AVG(UNIX_TIMESTAMP(last_updated)) FROM {{post}}');

 $criteria=new CDbCriteria;

 $criteria->order='post_id DESC';

 $models=self::model()->cache(1000,$dependency)->findAll($criteria);

 return $models;

            

}



Then, somewhere in a widget, let’s call it widget A i call:




$models=Post::a();



then the posts will be cached, each post model having only the post_id and title attributes loaded.

Next, if in another widget, let’s call it widget B, which gets called after widget A has been called, i do:




$models=Post::b();



because i want to get all the post attributes, not only the title and post_id(like i did in widget A), then i only get the post_id and the post title, because the dependency has been evaluated in Post::a() and used in Post::b() which is not correct.

How can i avoid this behavior ?

I don’t think it would ever happen, because Post::a() and Post::b() are cached in the different cache entries. Query caches uses the SQL to create the cache entry id(index).

http://www.yiiframework.com/doc/guide/1.1/en/caching.data#query-caching

BTW, just out of curiosity, why ‘AVG’ not ‘MAX’?

I mean, the sql for CDbCacheDependency must be very light-weighted because it is executed every time the cache is accessed. So I think ‘MAX’ is more appropriate for the purpose.

It does ? because it is not clear to me it does it, i mean in the docs it says that if the dependency has changed then the cache is invalidated, and basically i have same dependency for both class methods.

When you say "Query caches uses the SQL to create the cache entry id(index)." you mean the dependency sql or the actually query which should retrieve the models list ?

Honestly i don’t know the answer right now, i remember i ran into troubles long time ago using only MAX and the solution that worked was AVG and i am using it since then.

The actual query. The hash of it is used as the cache entry id.

As the doc says, at first the cache entry is searched for.

And if the entry is found, then the validity and the dependency will be evaluated.

The dependency definition (e.g. dependency sql) and the evaluated result are both stored in each cache entry along with its contents … that means the dependency check will be done AFTER the cache entry has been retrieved successfully.

Okay, thanks for explaining this, it makes sense now :)

I remember now why you should use AVG and NOT MAX.

If you have something like:




$dependency=new CDbCacheDependency('SELECT MAX(last_updated) FROM {{post}}');

$criteria=new CDbCriteria;

$criteria->order='post_id DESC';

$models=self::model()->cache(1000,$dependency)->findAll($criteria);

foreach($models AS $model){

 echo $model->title;

}



And let’s say the above query returns 10 models, all 10 models will be cached for the next requests, but if you delete one of those 10 records from the database (not the last updated one, on which the depenency is created on by using MAX()) then in frontend you will still receive 10 models, when in fact the cache should invalidate and you should retrieve 9 models.

Makes sense ?

Ah, yes, it does make sense. “MAX” doesn’t reflect a deletion. I’ve recalled it now.

I had completely forgotten that I once got the same problem.

My workaround has been CGlobalStateCacheDependency instead of CDbCacheDependency. I store the last create, update or delete time of a table in a global state, and use it for the dependency check.

Not an elegant solution … error-prone :(