Reputation: 2405
I'm hoping this is the correct place to ask this, but after recently experiencing some strange behaviour I realised after doing some research that when using .NET memory cache and you retrieve an object from cache you retrieve a reference to that object in cache, rather than a copy of the object, so any updates to the object will persist in cache.
In the example below the student is updated in the StudentController
, and retrieved again the CourseController
, with the student containing the updated value without having to refresh the cache.
My initial approach was to clear the cached students collection after updating the DB (because I thought the cached version wouldn't have included the update), but given that this persistence exists is there a need to repopulate the cache again once the database has been updated?
// Student controller
public class StudentController : Controller
{
// omitted for brevity.
public ActionResult UpdateStudent(int id)
{
var student = CollegeCache.Students[id];
student.FirstName = "SpongeBob"
studentRepository.update(student)
// CollegeCache.clearStudents();
}
}
// Course controller
public class CourseController : Controller
{
// omitted for brevity.
public ActionResult GetCoursesDetails(int id)
{
var student = CollegeCache.Students[id];
// here student.FirstName will be "SpongeBob", and not it's original value.
}
}
// Cache helper class
public static class CollegeCache
{
private static readonly ObjectCache cache = new MemoryCache("College");
private static object locker = new object();
public static readonly string StudentsKey = "StudentsKey";
// Clears the entire cache store.
public static void Clear()
{
foreach (var item in cache)
cache.Remove(item.Key);
}
// Clears a single cache entry.
public static void Clear(string key)
{
cache.Remove(key);
}
// Add to cache helper
private static void Add(string key, object value, DateTimeOffset expiration,
CacheItemPriority priority = CacheItemPriority.Default)
{
var policy = new CacheItemPolicy();
policy.AbsoluteExpiration = expiration;
policy.Priority = priority;
var item = new CacheItem(key, value);
cache.Add(item, policy);
}
// Students cache store.
public static Dictionary<int, Student> Students
{
get
{
var dictionary = cache[StudentsKey] as Dictionary<int, Student>;
if (dictionary == null)
{
lock (locker)
{
dictionary = db.Students.All().ToList().ToDictionary(a => a.Id);
Add(StudentsKey, dictionary, DateTime.Now.AddHours(1));
}
}
return dictionary;
}
}
// Clears the users cache store.
public static void ClearStudents()
{
Clear(StudentsKey);
}
}
Upvotes: 2
Views: 13188
Reputation: 5832
Generally speaking, if you update data in your underlying data source then you must also update it in the cache otherwise the future get of data in your cache is stale and inconstant state than the data in your DB. you would be out of sync. You could clear the cache and repopulate but that would be an expensive thing to do every time there is an update - it is NOT recommended to do this for the reasons outlined above. You should only update when you have updated your data in your DB successfully and then update the cache.
Since you update the object in question, the cache should be updated "automatically" in a way (provided that you obtained the object from the cache) however I still would do an explicit update on the cache side because what if the data source threw an error (i.e SQLException)? you need to ensure that the object in question is updated accurately otherwise you have data integrity issues :)
Upvotes: 3