Caching
Watch the Caching video on YouTube.
Every time an application retrieves the same data again, it wastes time and CPU cycles. Sometimes simple caching is enough, sometimes you need more, and how you cache often depends on the situation. PLINQO provides a query result cache, cache profiles, cache groups, cache providers and a cache manager, so you can configure caching to meet your application's needs as they change. Providers include the HttpCacheProvider and a Memcached provider.
The caching libraries, including the Memcached provider (CodeSmith.Data.Memcached), are in the templates' Common folder. The Tracker sample application shows caching in use.
Query result cache
PLINQO can cache the result of any LINQ to SQL query. It stores results with the System.Web.Caching.Cache class, and you can use a sliding or absolute expiration and set a priority on cached items.
To cache a query result, use the FromCache extension method in the CodeSmith.Data.Linq namespace. Run the query as you normally would, then append FromCache and tell PLINQO how to cache the results:
//query is cached using the default settings
var tasks = context.Task.ByAssignedId(UserId).FromCache();
//query result is now cached 300 seconds
var approvedUsers = context.User.ByIsApproved(true).FromCache(300);
Each query is cached separately.
Cache profiles
How you cache often depends on the scenario. A drop-down list that rarely changes has different caching needs than a user's task list, and possibly needs a different provider. Cache profiles are a simple way to configure the cache settings for each scenario. Here's a sample configuration:
<configuration>
<configSections>
<section name="cacheManager" type="CodeSmith.Data.Caching.CacheManagerSection, CodeSmith.Data" />
</configSections>
<cacheManager defaultProvider="HttpCacheProvider" defaultProfile="Short">
<profiles>
<add name="Short" description="Short cache" duration="0:5:0" />
<add name="ShortSliding" description="Short sliding cache" duration="0:5:0" mode="Sliding" group="MyGroup" />
<add name="Long" description="Long cache" duration="1:0:0" />
</profiles>
<providers>
<add name="MemcachedProvider" description="MemcachedProvider"
type="CodeSmith.Data.Memcached.MemcachedProvider, CodeSmith.Data.Memcached" />
<add name="HttpCacheProvider" description="HttpCacheProvider"
type="CodeSmith.Data.Caching.HttpCacheProvider, CodeSmith.Data" />
</providers>
</cacheManager>
...
</configuration>
To use Memcached, also specify your Memcached servers:
<configuration>
<configSections>
<section name="cacheManager" type="CodeSmith.Data.Caching.CacheManagerSection, CodeSmith.Data" />
<sectionGroup name="enyim.com">
<section name="memcached" type="Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching" />
</sectionGroup>
</configSections>
<enyim.com>
<memcached>
<servers>
<add address="127.0.0.1" port="11211" />
<add address="127.0.0.2" port="11211" />
</servers>
<socketPool minPoolSize="10" maxPoolSize="100" connectionTimeout="00:00:10" deadTimeout="00:02:00" />
</memcached>
</enyim.com>
<cacheManager defaultProvider="HttpCacheProvider" defaultProfile="Short">
<profiles>
<add name="Short" description="Short cache" duration="0:5:0" />
<add name="ShortSliding" description="Short sliding cache" duration="0:5:0" mode="Sliding" group="MyGroup" />
<add name="Long" description="Long cache" duration="1:0:0" />
</profiles>
<providers>
<add name="MemcachedProvider" description="MemcachedProvider"
type="CodeSmith.Data.Memcached.MemcachedProvider, CodeSmith.Data.Memcached" />
<add name="HttpCacheProvider" description="HttpCacheProvider"
type="CodeSmith.Data.Caching.HttpCacheProvider, CodeSmith.Data" />
</providers>
</cacheManager>
...
</configuration>
This configuration has two providers, the default HttpCacheProvider and the Memcached provider, and defines a few named profiles: use the HttpCacheProvider for short cache durations and the Memcached provider for anything cached for a long time. If you don't specify a profile when you cache data, the Short profile is used. When you cache an item, you don't have to worry about settings; just tell PLINQO which profile to use:
var project = db.Project
.ById(projectId.Value)
.FromCacheFirstOrDefault("Short");
Cache groups
You can store cached items as a group: when you cache a query result, give the name of the group it belongs to. Groups make invalidating the cache simple, because the code that invalidates a group doesn't need to know which items are in it:
public ActionResult MyTasks(int userId)
{
// will be separate cache for each user id, group all with name MyTasks
var tasks = db.Task
.ByAssignedId(userId)
.ByStatus(Status.InProgress)
.FromCache(CacheManager.GetProfile().WithGroup("MyTasks"));
return View(tasks);
}
public ActionResult UpdateTask(Task task)
{
db.Task.Attach(task, true);
db.SubmitChanges();
// since we made an update to the tasks table, we expire the MyTasks cache
CacheManager.InvalidateGroup("MyTasks");
}
When a task is updated, UpdateTask only has to invalidate the MyTasks group. It doesn't need to know about the related cached items, only that a group of items is out of date because the method ran.
Cache manager
PLINQO's cache manager has a simple API to store, retrieve and remove items from the cache:
CacheManager.Set("user-17", user, 30);
User user = CacheManager.Get("user-17");
CacheManager.Remove("user-17");