user1017882
user1017882

Reputation:

Best caching strategy in this particular scenario

I am retrieving a big list of news items.

I want to utilise caching of this list for obvious reasons (running a query any more than necessary won't do).

I bind this list to a repeater on which I have extended to enable paging (flicking between pages causes page load and so a retrieval of the list again).

The complication is the fact that these news items can also be queried by date from a query string 'year' that is present only when querying the news items by date.

Below is pseudo code for what I have so far (pasting the real code here would take too much time trimming out all of the bits that just add confusion):

if(complete news items list are not cached OR querystring["year"] != null)
{
   Int year = queryString["year"] (could be null)
   Cache.Add(GetNewsItems(year));
}
else
{
   return cached newsItems;
}

The problem is that when the news items page loads (because of a paging control's postback) the querystring's [year] parameter will still be populated and so will re-do the GetNewsItems. Also - even if the home URL (i.e. no query string) is then navigated to - in effect there is still a cached version of the news items so it will not bother to try and retrieve them - but they MAY be there for a particular year and so aren't relevant to an 'all years' kind of search.

Do I add a new cache entry to flag what most recent search was done? What considerations do I have to make here to cache timing out? I can add a new query string if needs be (preferably not) - would this solve the problem?

Upvotes: 3

Views: 270

Answers (2)

Nibor
Nibor

Reputation: 1116

Could you get the complete list on the first query, and cache this (presuming it is not too enormous)? Then for any subsequent queries get the data from the cache and query it to filter out just the year you want.

Maybe you could store the data in the cache in the form of

IDictionary<int, IEnumerable<NewsItem>> 

(assuming there are more than one NewsItem for a year) where the key is the year so you can just retrieve a single dictionary value pair to get a year's data.

Alternatively cache the data by year, as you are doing in your sample, and implement a mechanism to get data from the cache for each year if it exists. When getting all, you can either just get all from the data store and cache this separately or implement some mechanism to determine what years are missing from the cache and just get these. Personally, I think I would go with caching all and filtering data from the cache so as to not clog up the memory with too much cached data.

A useful TryGetValue pattern to get from cache is something like:

private bool TryGetValue<U>(string key, out U value)
    {
        object cachedValue = HttpContext.Current.Cache.Get(key);
        if (cachedValue == null)
        {
            value = default(U);
            return false;
        }
        else
        {
            try
            {
                value = (U)cachedValue;
                return true;
            }
            catch
            {
                value = default(U);
                return false;
            }
        }
    }

Upvotes: 2

Tisho
Tisho

Reputation: 8482

Not sure if this might help for your case, but you can add the repeater to an user control, and enable OutputCache for it, to be invalidated by POST/GET params:

<%@ OutputCache Duration="100" VaryByParam="year" %>

Upvotes: 1

Related Questions