Question

I'm using the Massive micro-ORM with a new project. I added some caching, and it all appeared to work - until I realize that the cached objects (dynamic) are still querying the database. This kills the whole point of caching.

What would be the easiest way to disconnect the result set from the database. Nearly all calls are read-only.

I'm using code like this to query records:

public static dynamic GetActive()
{
    return Caching.LoadFromCache("Units_GetActive", 120,
        () =>
        {
            dynamic tbl = new Units();
            return tbl.Find(Enabled: 1, orderby: "SortOrder");
        });
}

My caching code looks like this:

public static dynamic LoadFromCache(string cacheKey, int secondsToCache, Func<object> query)
{
    object tocache = null;

    // result will always get the value here
    // tocache will only have the value when it was pulled from our method
    object result = MemoryCache.Default[cacheKey] ?? (tocache = query.Invoke());

    if (secondsToCache > 0)
    {
        if (tocache != null) // only save to cache if it wasn't there
            MemoryCache.Default.Add(cacheKey, tocache, DateTime.UtcNow.AddSeconds(secondsToCache));
    }
    else
    {
        // remove from cache only if secondsToCache was zero or less
        MemoryCache.Default.Remove(cacheKey);
    }

    return result;
}

The caching code works. The problem is the dynamic object returned (IEnumerable<dynamic>) opens another connection to the database.

Ideas?

Was it helpful?

Solution

Tim Medora had the right idea.

I changed my caching code to this:

public static dynamic LoadFromCache(string cacheKey, int secondsToCache, Func<object> query)
{
    object tocache = null;

    // result will always get the value here
    // tocache will only have the value when it was pulled from our method
    object result = MemoryCache.Default[cacheKey] ?? (tocache = query.Invoke());

    if (secondsToCache > 0)
    {
        // If this came from Massive, we need to get the list instead of opening a 
        // database connection each time we enumerate.  I check the type, because other things
        // are stored.
        if (tocache is IEnumerable<dynamic>)
        {
            tocache = ((IEnumerable<dynamic>)tocache).ToList<dynamic>();
            result = tocache;
        }

        if (tocache != null) // only save to cache if it wasn't there
            MemoryCache.Default.Add(cacheKey, tocache, DateTime.UtcNow.AddSeconds(secondsToCache));
    }
    else
    {
        // remove from cache only if secondsToCache was zero or less
        MemoryCache.Default.Remove(cacheKey);
    }

    return result;
}

The ToList<dynamic>() was the key part. It seems to work as expected now. ToList<T> is an extension method in the System.Linq namespace.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top