Cache invalidation with nested objects

As we know:

Hi everyone

I’d like to talk to you about a topic that I’ve been carrying around since I’ve been a developer without ever finding the perfect solution: cache invalidation with nested objects.

This is the scenario:

Product.cfc:

property name="id" type="String"
property name="category" type="Category"

Category.cfc:

property name="id" type="String";

When I read a “Category”:

function getCategory( id ) {

     // check that the object is not already in cache
     // if yes, return it

     if ( cacheIdExists("category_" & id) ) {

         return cacheGet( "category_" & id )

     } else {

        // Otherwise I create it

         var categoryBean = new Category();

         var categoryFromDB = getDAO().select( id = id );

         categoryBean.setId( categoryFromDB.category_id );
        
         cachePut( "category_#id#", categoryBean );

         return categoryBean;

     }
}

When I read “Product”:

function getProduct( id ) {

     // check that the object is not already in cache
     // if yes, return it
     if ( cacheIdExists( "product_" & id) ) {

         return cacheGet( "product_" & id )

     } else {

         // Otherwise I create it
         var productFromDB = getDAO().select( id = id );

         var productBean = new Product()

         productBean.setId( productFromDB.product_id );

         // get the category from model
         var categoryBean = getCategory( productFromDB.category_id );
         productBean.setCategory( categoryBean );

         cachePut( "product_#productFromDB.product_id#", productBean );

         return productBean;

     }
}

As you can see, I cached the entire “Product” object, including its “Categoy” children.
But now I have the problem that when I edit a category, I should invalidate the cache of all linked “Product” objects.

It’s quite simple when there’s a parent and a few children, but it gets really complex if there are many, very nested children, children, children…

The solutions that I have found and that I apply depending on the complexity are these:

  1. Clear the parent cache by hand (in our example all the “Products” that have the category changed. It works, but it’s complicated with many parents/children).
  2. Don’t put the nested properties like “Category” in the “Product” bean but use a service to get all the category of a product. It’s not as solid as I would like.
  3. Use an event system that removes as in point 1. It is more complex but it also works with complex objects. In this case i could use the CacheBox events.
  4. Don’t cache all the “Product” object, but create it every time. It’s a good solution because it generally decreases the load on the db a lot anyway, but I would prefer that my code doesn’t do useless things like always creating the same object when it hasn’t been modified yet. And then I don’t really like caching the data that comes from the DB.

I was trying to figure out if CacheBox could take care of these “cascading deletions” for me.
I could use both CacheBox events (afterCacheElementRemoved, afterCacheElementUpdated methods) and listeners.

I hope I made myself clear.

Before I start coding, I’d like to hear your opinion.

I wish a wonderful New Year to all the guys who keep this community alive.

As usual, many many many thanks :blush: