Hibernate version: EJB RC3 patch 1
Problem: I have watched in my debugger the cascade mechanism triggering the initialization of a series of previously uninitialized (lazy) collections when no persist, merge or remove call was made (only read operations). This does not look like intended behavior, and causes much unnecessary database I/O.
Here are the highlights of the call graph within Hibernate during the problem:
Code:
EJBTxPolicy.endTransaction()
TransactionImpl.commit()
EntityManagerImpl.flush()
SessionImpl.flush()
EJB3FlushEventListener.cascadeOnFlush()
Cascade.cascade()
Cascade.cascadeCollection()
CascadingAction.getCascadableChildrenIterator()
PersistentSet.iterator()
SessionImpl.initializeCollection()
// ...Hibernate procceeds to issue the undesired select statement...
OneToManyPersister.initialize()
Here is the application context (four levels of parent/child) in simplified, understandable terms:
I have an entity Country with a OneToMany collection States.
The State entity has a OneToMany collection Counties.
The County entity has a OneToMany collection Townships.
The Township entity has a OneToMany collection Cities.
All of the collections are FetchType.LAZY, and CascadeType MERGE, PERSIST, REMOVE.
The presentation layer already has a list of Country objects. When the States collection is needed, I pass the selected detatched Country object to a DAO function, listStates(Country). The DAO is a Stateless bean.
Code:
Set<State> listStates(Country country) {
em.refresh(country); //reattach detached country
Set<Section> set = country.listStates(); //get the list of sections
int size = set.size(); //get the number of states (causes lazy init)
return set //return the states for this country
}
Inside the Country class:
Code:
private Set<State> getStates(){
return states;
}
@Transient
public Set<State> listStates() {
return getStates();
}
After the DAO function returns, Hibernate automatically ends the transaction started by the EntityManager when the DAO function was called, beginning the call graph above.
Hibernate then proceeds to initialize the County collection for each State, and the Township collection for each County.
This is a lot of database activity, an is undesirable for performance reasons.
All that was requested of the DAO tier was the State collection, which resulted in only one SELECT.
After returning the State collection successfully, the framework proceeds to read in the rest of the unneeded data in the name of Cascade functionality, and delays the results of the call to the client until finished.
I would appreciate any insights into this issue from the community. Thank you.