Teneo/Hibernate/Collection Extra-Lazy Loading
As a default collections are lazy loaded, this means that a collection is loaded in memory when it is first accessed but not before.
There are however collections which are to large to load in memory for standard operations. For these collections the standard lazy behavior is not enough (as the collection gets completely loaded at first access). For these collections it can make sense to make use of the Hibernate extra-lazy functionality. Teneo supports this functionality and facilitates its use.
See this blog for some information on Hibernate extra-lazy behavior.
Hibernate only supports extra-lazy loading for lists which are bi-directional and for which the elements have an explicit property/member for the list-index. Teneo makes it possible to also use the Hibernate extra-lazy mode for uni-directional associations when the list-index is not mapped. Teneo does this by creating so-called synthetic properties which take care of storing this information.
As Hibernate needs the list-index to be present as a member in the element it means that EAttribute lists (which contain only primitive elements) have limited extra-lazy behavior (get and size operations).
With extra-lazy handling of EReference lists the following operations are executed through individual calls to the database (instead of loading the complete collection in memory):
- remove last element in the list
Note that for smaller collections, the extra-lazy mode can be counter-productive as in these cases it makes sense to read the collection in one sql statement instead of individual sql statements for individual operations.
Enabling Extra-Lazy Mapping
Extra-lazy handling can be enabled in two ways:
- By setting the option PersistenceOptions.FETCH_ASSOCIATION_EXTRA_LAZY
- By setting the fetch attribute of the OneToMany annotation to EXTRA: @OneToMany(fetch=EXTRA)
The first option sets extra-lazy for all one-to-many associations, the annotation is useful for when selecting extra-lazy for specific associations.
Teneo provides a special utility class for lazy handling of a collection. These utility methods work for both extra-lazy collections as well as collections which are not extra-lazy. The class is: org.eclipse.emf.teneo.hibernate.LazyCollectionUtils. This class offers two utility methods:
- size: this method performs a database count to determine the collection size (instead of loading the collection into memory)
- getPagedLoadingIterator: this method returns an iterator (over a collection) which loads the data from the collection in pages from the database. While iterating previous pages of data are discarded and new ones are read from the database.
Choosing an Alternative Mapping
Another approach (than using extra-lazy) is to choose another mapping approach.
When you encounter a very large collection in your model then you can also decide to not explicitly map this collection to the database but map the 'other side'.
So assume that you have a type called 'Root' which has a collection efeature 'leafs' with thousands of children (the 'Leaf' type). Instead of mapping the collection to the database it can be an option to only map the reference from Leaf to Root (so from child to parent). The Root.leafs collection can then be made transient (using a @Transient annotation). Then when working with the data in your application you can query directly for specific Leaf objects using a Root object as the filter.