1

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);
        }
    }   
Community
  • 1
  • 1
Mark Erasmus
  • 2,305
  • 6
  • 25
  • 37
  • well yes. 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 everytime there is an update. you should only update when you have updated your data in your DB and then update the cache – Ahmed ilyas Sep 15 '15 at 21:45
  • one thing I noted is that you do not show where and how "cache" is defined. it would be good if you can post that but in any event, the comment I made above still applies :) – Ahmed ilyas Sep 15 '15 at 22:01
  • @Ahmedilyas I understand that the cache store needs to be in sync with the data store, and that's what I was trying to explain. When I update an object that is stored in cache I don't need to clear and refresh the cache - the cache is updated when I update the object (i.e., without having to refresh the cache). I've updated the code to include the full cache implementation now. – Mark Erasmus Sep 15 '15 at 22:41
  • Thanks for the code update Mark. yes - 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 :) good stuff! – Ahmed ilyas Sep 16 '15 at 06:37
  • @Ahmedilyas Thanks, that approach makes sense. – Mark Erasmus Sep 16 '15 at 14:20
  • I'll write my answer - feel free to accept. – Ahmed ilyas Sep 16 '15 at 14:48

1 Answers1

1

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 :)

Ahmed ilyas
  • 5,722
  • 8
  • 44
  • 72
  • "you could clear the cache and repopulate but that would be an expensive thing to do every time there is an update. You should only update when you have updated your data in your DB and then update the cache" Aren't these two the same thing? – Mark Erasmus Sep 16 '15 at 15:46
  • Are you basically saying clear the cache every time you do a DB update, but this is an expensive operation? – Mark Erasmus Sep 16 '15 at 15:53
  • no, that's not what I am saying :) I am saying do NOT clear the entire cache after every DB Update. only update the particular/related items in cache when you do a successful DB update. – Ahmed ilyas Sep 16 '15 at 16:43
  • Oh right - that makes more sense! :) But yes, that is my approach - I only clear the affected cache stores. e.g. if I update a student I clear the students collection stored in cache, and leave the others unaffected, unless a dependency exists between the cache stores. – Mark Erasmus Sep 16 '15 at 16:53