Database: MS SQL Server 2005
Hibernate version: 3.2.0
I'm having trouble getting my one-to-one associations to load correctly from Hibernate's second-level cache. I have one particular HQL query, the results of which I'm caching using the query cache, and all of my other entities are added/loaded from the cache correctly; it's just my one-to-one associates that get added to the cache, but are being loaded from the database every time I run my HQL query (and afterward added once again to the cache, only to be ignored by subsequent executions of the same query).
I have the query cache turned on, second-level cache turned on, and I'm using EH Cache as my cache provider. Nearly everything is configured with a read-only cache strategy. I'm using Spring, and the relevant pieces of my configuration look like this:
Code:
<bean id="hibernateProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="properties">
<props>
...
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
<prop key="hibernate.cache.provider_configuration_file_resource_path">/passcodeserver/ehcache.xml</prop>
...
</props>
</property>
</bean>
<bean id="APSHibernateSessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
...
<property name="entityCacheStrategies">
<props>
...
<prop key="com.choruscall.db.table.Account">read-only</prop>
<prop key="com.choruscall.db.table.Registrant">read-only</prop>
<prop key="com.choruscall.db.table.RegistrantPIN">read-only</prop>
...
</props>
</property>
<property name="collectionCacheStrategies">
<props>
<prop key="com.choruscall.db.table.Account.registrants">read-only</prop>
....
</props>
</property>
<property name="hibernateProperties" ref="hibernateProperties" />
</bean>
The specific entities - an Account with a set of Registrant objects. Each Registrant has a one-to-one relationship with a RegistrantPIN object. In the database, the RegistrantPin table has RegistrantID column that has a a foreign key relationship with RegistrantID in the Registrant table.
Code:
<class name="Account" table="Account" >
...
<set name="registrants" cascade="all, delete-orphan" inverse="true">
<key column="AccountID"/>
<one-to-many class="Registrant"/>
</set>
...
</class>
<class name="Registrant" table="Registrant">
...
<one-to-one name="registrantPin" class="RegistrantPIN"
property-ref="registrant" cascade="all"/>
...
</class>
<class name="RegistrantPIN" table="RegistrantPin">
...
<many-to-one name="registrant" column="registrantID" class="Registrant"
cascade="all"/>
...
</class>
In my application, I'm repeatedly running an HQL query that loads an Account object and forces initialization of the lazy registrants collection (via left join fetch). The Account object and the list of Registrant objects are put/loaded from the cache correctly, but the RegistrantPIN objects are coming from the database every time. Here is an excerpt from the cache log:
Code:
DEBUG - [17:40:09, 596]: org.hibernate.cache.EhCache.get Element for sql: <SQL removed because the query is huge and probably irrelevant>
DEBUG - [17:40:09, 597]: org.hibernate.cache.StandardQueryCache.get query results were not found in cache
...
DEBUG - [17:40:10, 185]: org.hibernate.cache.ReadOnlyCache.put Caching: com.choruscall.db.table.Registrant#341
DEBUG - [17:40:10, 190]: org.hibernate.cache.ReadOnlyCache.put Caching: com.choruscall.db.table.RegistrantPIN#46
...
DEBUG - [17:40:28, 836]: org.hibernate.cache.EhCache.get key: sql: <removed again, same SQL>
DEBUG - [17:40:28, 837]: org.hibernate.cache.StandardQueryCache.isUpToDate Checking query spaces for up-to-dateness: [ActivePasscodes, Form, Event, Account, Registrant, AudioEvent, Conference]
...
DEBUG - [17:40:28, 843]: org.hibernate.cache.StandardQueryCache.get returning cached query results
...
DEBUG - [17:40:28, 958]: org.hibernate.cache.ReadOnlyCache.get Cache hit: com.choruscall.db.table.Registrant#341
DEBUG - [17:40:28, 961]: org.hibernate.cache.ReadOnlyCache.put Caching: com.choruscall.db.table.RegistrantPIN#46
It's caching the RegistrantPIN object with identifier #46 again after having previously cached it 18 seconds prior. A database profiler confirms that the RegistrantPIN objects are being loaded from the database every time my HQL query is executed.
My situation seems extremely similar to another post I found in the NHibernate forums:
http://forum.hibernate.org/viewtopic.php?p=2378461
I tried setting fetch="select" on the many-to-one side as Karl suggests in that thread, but still had no luck. Just like the guy in that post, I'd like for my RegistrantPIN associations to be loaded from the second-level cache rather than the database every time a Registrant is loaded from the cache. I'm guessing it's a problem with my mapping that's causing this, but I'm pretty stuck at this point. Any ideas?
John