Wednesday, September 15, 2010

Maintaining L2 Cached Collections After Cascade Remove

Hibernate's L2 collection caching provides a major performance boost to our application. It's requires an odd mindset from the developer user however - it does some things automatically, but the developer is left with a few critical responsibilities. If you just configure a collections cache but fail to maintain the collection cache properly in your code you can expect problems.

This is very error prone - the developer needs to understand a great deal about how Hibernate's collections caches work 'under the covers' to get everything working just perfectly.

The simple example is removing (deleting) an entity that is a member of a parent's collection. Lets assume I have entities Child and Parent. Parent has a cached collection called 'children'. If I simply do:

childDAO.delete(aChildEntity);

I'm now in bad shape. The parent cached collection still thinks it contains the child that has been removed. Simple enough; the developer is responsible for maintaining the collection (I know I know this code is for illustration only):

aChildEntity.getParent().getChildren().remove(aChildEntity); childDAO.delete(aChildEntity);

Problem solved right? Now lets make the scenario more complex. I have another entity that also cascades delete to children, so it's happening implicitly. Maybe I have 5 or 10 places where this happens. I'm quickly going to have to write a lot of fragile code to make sure this works right.

Instead, what I've done is to use a @PreRemove method on Child to evict the parent collection from the cache. This should be far less fragile. No matter what new and creative ways I come up with of deleting children, the cache should stay clean:

sessionFactory.getCache().evictCollection(com.mycompany.entity.Parent.class.getName() + ".children", deletedEntityId);