1 Reply Latest reply on Jun 4, 2009 2:22 PM by adamw

    Eager loading - HHH-3552

    aslak

      Hi Adam!

      I've been banging my head agains the wall due to lack of http://opensource.atlassian.com/projects/hibernate/browse/HHH-3552 for some time now..
      so long that I figured I would have a go at it.. :)

      The easies way, as far as I can see(without having any deep understanding of the code) seems to be to add a set of Eager proxies
      the same way the Lazy proxies are added, but without the lazy loading of the delegate from the Initializor.

      This is what I've changed so far..

      public class PropertyAuditingData {
       ...
       private String fetchType = "LAZY";
       ...
       public String getFetchType() {
       return fetchType;
       }
      
       public void setFetchType(String fetchType) {
       this.fetchType = fetchType;
       }
       ...
      }
      
      public class AuditedPropertiesReader {
      
       ...
       private boolean fillPropertyData(XProperty property, PropertyAuditingData propertyData,
       ...
       setFetchMode(property, propertyData);
       ...
       }
      
       private void setFetchMode(XProperty property, PropertyAuditingData propertyData) {
       OneToMany oneToMany = property.getAnnotation(OneToMany.class);
       if(oneToMany != null) {
       propertyData.setFetchType(oneToMany.fetch().toString());
       }
       ManyToOne manyToOne = property.getAnnotation(ManyToOne.class);
       if(manyToOne != null) {
       propertyData.setFetchType(manyToOne.fetch().toString());
       }
       OneToOne oneToOne = property.getAnnotation(OneToOne.class);
       if(oneToOne != null) {
       propertyData.setFetchType(oneToOne.fetch().toString());
       }
       ManyToMany manyToMany = property.getAnnotation(ManyToMany.class);
       if(manyToMany != null) {
       propertyData.setFetchType(manyToMany.fetch().toString());
       }
       }
       ..,
      }
      
      public final class CollectionMetadataGenerator {
      
       ...
       private void addMapper(CommonCollectionMapperData commonCollectionMapperData, MiddleComponentData elementComponentData,
       MiddleComponentData indexComponentData) {
      
       ...
       } else if (type instanceof BagType) {
       Class<? extends List> listProxyType = ListProxy.class;
       if("EAGER".equals(propertyAuditingData.getFetchType())) {
       listProxyType = EagerListProxy.class;
       }
       currentMapper.addComposite(propertyAuditingData.getPropertyData(),
       new BasicCollectionMapper<List>(commonCollectionMapperData,
       ArrayList.class, listProxyType, elementComponentData));
       } else if (type instanceof ListType) {
       ...
       }
       ...
      }
      
      public abstract class EagerCollectionProxy<U, T extends Collection<U>> implements Collection<U>, Serializable {
       ...
       public EagerCollectionProxy(Initializor<T> initializor) {
       delegate = initializor.initialize();
       }
       ...
      }
      
      public class EagerListProxy<U> extends EagerCollectionProxy<U, List<U>> implements List<U>, Serializable {
       ...
       public EagerListProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<List<U>> initializor) {
       super(initializor);
       }
       ...
      }
      


      The code above only add eager support to JPA annotated beans of BagType for now..

      Is this the right way to go?


      Some questions:
      How to add support for eager loading based on hibernate xml configuration? (is it even supported?)

      All the org.hibernate.envers.entities.mapper.relation PropertyMapper implementations seem to be tightly connected
      to the org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor implementations witch is a part of the lazy package.
      Should the Initializors be moved out of the lazy package to a higher level and reused inbetween eager/lazy, or should there be implemented a new set of mappers to create the eager proxies(maybe use the value directly, without the need for a proxy)?
      IE:
      protected AbstractCollectionMapper(CommonCollectionMapperData commonCollectionMapperData,
       Class<? extends T> collectionClass, Class<? extends T> proxyClass) {
       this.commonCollectionMapperData = commonCollectionMapperData;
       this.collectionClass = collectionClass;
      
       try {
       proxyConstructor = proxyClass.getConstructor(Initializor.class);
       } catch (NoSuchMethodException e) {
       throw new AuditException(e);
       }
       }
      


      Are there other parts that need changes??

      -aslak-

        • 1. Re: Eager loading - HHH-3552
          adamw

          Hello,

          well, the first hard thing is that eager associations should be fetched in one query. Doing this would be quite hard currently.

          The other possibility is to execute a couple of queries, but "eagerly", meaning that the object returned would be safe to transport etc. Then the approach you took is ok.

          If you want to add eager loading based on hibernate configuration, I suppose there is somewhere a flag in the metadata descriptor of the association if it is eager or not.

          As for the PropertyMapper/Initializor, I guess that it would be better to leave PropertyMapper as it is (more or less), but just provide new implementations of Initializors which would do the eager loading.

          Adam