[hibernate-issues] [Hibernate-JIRA] Created: (HHH-2668) Caching Fails with Composite-Ids Containing Nested, Complex Entities

Juan Osuna (JIRA) noreply at atlassian.com
Mon Jun 11 10:09:04 EDT 2007


Caching Fails with Composite-Ids Containing Nested, Complex Entities
--------------------------------------------------------------------

                 Key: HHH-2668
                 URL: http://opensource.atlassian.com/projects/hibernate/browse/HHH-2668
             Project: Hibernate3
          Issue Type: Bug
          Components: caching (L2)
    Affects Versions: 3.2.4.sp1
         Environment: Problem is independent of environment or platform and most likely exists in prior versions.
            Reporter: Juan Osuna
         Attachments: hibernate-caching-fix.zip

Description of Failing Test Case Scenario

Preconditions: An entity class is mapped that uses a composite-id that contains a nested entity class. Only the composite-id class implements equals/hashcode, not the nested entity class. 

Steps to Reproduce:
1.	open session and fetch object using composite-id
2.	open new session and fetch same object again using different instance of composite-id but with same identity

Invalid Postconditions: On second retrieve, Hibernate fails to get the object from the cache and unnecessarily reloads the object. CachKeys containing different instances of the composite-id always fail to be equal even though they have the same persistent identity.

Attachment Contents

Code fix is attached as well as a Junit test case that reproduces the problem and validates the fix. The full Hibernate suite was also executed with no impact. 

Attachment contains:

New Test Method:
org.hibernate.test.cache.BaseCacheProviderTestCase.testQueryCacheComplexItem

New Test Entity Items:
org\hibernate\test\cache\ComplexItem.hbm.xml
org.hibernate.test.cache.ComplexItem
org.hibernate.test.cache.ComplexItemPK

Code Fix:
org.hibernate.cache.CacheKey (see FIX comments)

Problem and Fix Details

Hibernate generally strives to use persistent identifiers for managing object identity rather than the equals/hashcode methods implemented by entity classes. While it is good practice to implement equals/hashcode, Hibernate does not generally force users to do this. 

When wrapping a composite-id object, the current implementation of CacheKey fails to recurse through nested complex entities to query for equality based on persistent identity. Instead, when the recursion algorithm hits a complex entity, it invokes equals directly on that entity rather than further recursing through the identifier object.

Notably, the recursion logic for equals is not symmetrical with the recursion logic for hashcode, which does recurse through identifier objects. So, while CacheKey never invokes hashcode on nested complex entities, it does invoke equals on these entities. 

A simple fix to this inconsistency is to store the factory parameter passed to CacheKey and later pass that parameter to the overloaded method: 
Type.isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory).

This fix restores symmetry to equals and hashcode behavior. By calling this overloaded method, the thread of execution will enter EntityType. isEqual(Object x, Object y, EntityMode entityMode, SessionFactoryImplementor factory), which correctly recurses through complex identifiers.

Design Principles

Hibernate should strive to behave predictably even in scenarios where users do not follow best practices. 

Hibernate should strive to be as forgiving as possible as long there is no negative consequence caused by such forgiveness. 

Hibernate should behave as consistently as possible. If Hibernate does not generally rely user-implemented equals/hashcode, it is best to avoid exceptions to this rule wherever possible. 

Possible Future Enhancement

Mapping composite-ids that contain complex entities can cause deep object graphs to be cached as part of CacheKey. This is unsettling because of it's potential to consume memory unnecessarily and unpredictably. 

Currently, CacheKey caches the hashcode by recursing through a complex graph of identifier objects. Perhaps, it would also be possible for CacheKey to cache an object graph of identifier objects whose leaves hold primitive values. This would further add symmetry between hashcode and equals and lighten the load for caching composite-ids that hold entity classes.

Robustly supporting composite-ids that hold complex identifiers seems like a worthwhile design goal. 



-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://opensource.atlassian.com/projects/hibernate/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        



More information about the hibernate-issues mailing list