さて、しばらくして、キャッシュにアクセスするための拡張メソッドを作成しました。
public static class MyExtensions
{
// temlplate for cache item key name
private const string CacheKeyTemplate = "{0}_{1}";
private static string GetCachePrefixByType(Type type)
{
// this is just sample, implement it any way you want
switch (type.Name)
{
case "Blog": return "b"; break;
case "BlogPost": return "bp"; break;
case "Comment": return "c"; break;
default: throw new NotImplementedException();
}
}
// insert with key containing object type custom prefix and object id
public static void Put(this Cache cache, object obj, long id)
{
cache.Insert(String.Format(CacheKeyTemplate, GetCachePrefixByType(obj.GetType()), id), obj);
}
// get by object type and id
public static T Get<T>(this Cache cache, long id)
{
return (T)cache[String.Format(CacheKeyTemplate, GetCachePrefixByType(typeof(T)), id)];
}
// get objects by WHERE expression
public static List<object> Get(this Cache cache, Func<object, bool> f)
{
return cache.Cast<DictionaryEntry>().Select(e => e.Value).Where(f).ToList();
}
// remove by object type and id
public static void Remove<T>(this Cache cache, long id)
{
cache.Remove(String.Format(CacheKeyTemplate, GetCachePrefixByType(typeof(T)), id));
}
// remove cache items by WHERE expression against stored objects
public static void Remove(this Cache cache, Func<object, bool> f)
{
foreach (string key in cache.Cast<DictionaryEntry>().Where(de => f.Invoke(de.Value)).Select(de => de.Key))
{
cache.Remove(key);
}
}
}
これが私のテストするクラスです:
private class Blog
{
public int BlogId { get; set; }
public string Name { get; set; }
}
private class BlogPost
{
public int PostId { get; set; }
public int BlogId { get; set; }
public string Text { get; set; }
}
private class Comment
{
public int PostId { get; set; }
public int CommentId { get; set; }
public string Text { get; set; }
}
およびテストコード自体:
// a blog
Blog blog = new Blog{ BlogId = 1, Name = "Jim" };
// two blog posts
BlogPost post1 = new BlogPost { PostId = 1, BlogId = 1, Text = "Aaaaaaaa" };
BlogPost post2 = new BlogPost { PostId = 2, BlogId = 1, Text = "Bbbbbbbbbb" };
// two comments to the 1st blog post
Comment comment11 = new Comment { CommentId = 11, PostId = 1, Text = "qwerty" };
Comment comment12 = new Comment { CommentId = 12, PostId = 1, Text = "asdfg" };
// one comment to the 2nd blog post
Comment comment21 = new Comment { CommentId = 21, PostId = 2, Text = "zxcvbn" };
// put it all to cache
HttpRuntime.Cache.Put(blog, blog.BlogId);
HttpRuntime.Cache.Put(post1, post1.PostId);
HttpRuntime.Cache.Put(post2, post2.PostId);
HttpRuntime.Cache.Put(comment11, comment11.CommentId);
HttpRuntime.Cache.Put(comment12, comment12.CommentId);
HttpRuntime.Cache.Put(comment21, comment21.CommentId);
// get post #2 by its id
BlogPost testPost = HttpRuntime.Cache.Get<BlogPost>(2); // testPost.Text = "Bbbbbbbbbb"
// get all comments for post #1
IEnumerable<Comment> testComments = HttpRuntime.Cache.Get(
x => (x is Comment) && ((Comment)x).PostId == 1).Cast<Comment>(); // comments 11 and 12 are in the list
// remove comment 21
HttpRuntime.Cache.Remove<Comment>(21);
// test if it was removed
comment21 = HttpRuntime.Cache.Get<Comment>(21); // null
// remove anything having text property = "qwerty"
HttpRuntime.Cache.Remove(x => x.GetType().GetProperty("Text") != null && ((dynamic)x).Text == "qwerty");
// test if comment 11 it was removed
comment11 = HttpRuntime.Cache.Get<Comment>(11); // null
// but comment 12 should still exist
comment12 = HttpRuntime.Cache.Get<Comment>(12); // it's there
// remove anything from cache
HttpRuntime.Cache.Remove(x => true);
// cache items count should be zero
int count = HttpRuntime.Cache.Count; // it is!