I am unable to get lazy loading with lazy="no-proxy" to work for loading of single associations (one-to-one, many-to-one) and was curious if anyone else has run into this issue. (Yes, I've done build time bytecode instrumentation. )
From looking at the source it looks there could be issues in two places -
1.
org.hibernate.cfg.HbmBinder.bindProperty() does not mark a property lazy if its lazy attribute is set to lazy="no-proxy".
if ( isLazyable ) {
Attribute lazyNode = node.attribute( "lazy" );
property.setLazy( lazyNode != null && "true".equals( lazyNode.getValue() ) );
}
This ultimately ends up as problematic for the org.hibernate.intercept.FieldInterceptor whose uninitializedFields field will not contain reference the property with lazy="no-proxy". The FieldInterceptor appears to get its values from the org.hibernate.tuple.PojoEntityInitializer which gets these values from looping through the properties on the POJO and querying their isLazy(). sets these is set to the properties that are marked lazy during the constructor of the org.hibernate.tuple.PojoEntityInitializer
2.
Once the above problem is worked around, the association is indeed lazily loaded on demand. But, unfortunately, during the cascade at the end of the transaction/session all associations are traversed it appears - regardless of whether they are marked as lazy="no-proxy". This has the side effect of actually loading the association that was marked as lazy - defeating the entire point of marking it lazy. I.e., this code in org.hibernate.engine.Cascade.cascade() has:
for ( int i=0; i<types.length; i++) {
CascadeStyle style = cascadeStyles[i];
if ( style.doCascade(action) ) {
// associations cannot be field-level lazy="true", so don't
// need to check that the field is fetched (laziness for
// associations is always done by proxying currently)
cascadeProperty(
persister.getPropertyValue( parent, i, eventSource.getEntityMode() ),
types[i],
style,
anything,
false
);
Seems like it should check to see whether the property has been touche or not. Is there a way to determine if the individual property is dirty or not? The only thing I could find to avoid the property access would be to check the FieldInterceptor to see if it was marked dirty or not. Are there better methods?
3.
Finally, I think it would be useful to add the following javadoc from FieldInterceptor to the reference docs. It can be a definte gotcha:
Note that this implementation assumes that the instance variable
* name is the same as the name of the persistent property that must
* be loaded.
I'm not a hibernate expert so perhaps my statements are off base. Is anyone else having similar problems?
Thanks!
|