Today I faced with next problem in hibernate:
My method:
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
List<Period> periods = _periodDAO.getPeriods(team);
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
}
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
Method initializeIssues:
public void initializeIssues(Period period) {
if (period.getIssues() != null) {
Hibernate.initialize(period.getIssues());
}
}
I receive exception if collection periods contains defaultPeriod
Caused by: org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:474)
at org.hibernate.Hibernate.initialize(Hibernate.java:417)
But if I remove some lines and change method to
@Transactional
public Period getDefault(Team team) {
Period defaultPeriod = team.getDefaultPeriod();
_periodDAO.initializeIssues(defaultPeriod);
return defaultPeriod;
}
It works fine.
I debugged first example and hibernate session does not close during whole method.
As I understand, if loaded object (one element in periods) in session has collection which associated with active session and existing before object (defaultPeriod) also has same association - it (defaultPeriod) will lose its association.
Is it truth? Who else faced with same problem?
Thank you for answers.
Presumably, your Team
argument is coming from another transaction and another Hibernate Session
.
When a @Transactional
method returns, the TransactionManager
closes the Session
which does some cleanup and unsets (sets to null
) the Session
field of all PersistentCollection
instances. Your defaultPeriod
has one of these in its issues
field.
Hibernate's Hibernate.initialize()
forces the initialization of a lazy PersistentCollection
, but has the following code (calls AbstractPersistentCollection#forceInitialization()
)
if ( session == null ) {
throw new HibernateException( "collection is not associated with any session" );
}
If you are planning on using the issues
collection outside the original @Transactional
method (the code that produces Team
), you need to load the underlying objects. Either change it to EAGER loading or do what you are doing with Hibernate.initialize()
.
Another solution is to make the Session
last longer than just the length of the first @Transactional
, but I don't have details for that. A quick google or SO search should bring up some options.
This is what is happening
Period defaultPeriod = team.getDefaultPeriod();
gets a Period
object with id (ex.) 42
. Because it happened in another Session
that has since been closed, the issues
is a PersistentCollection
which has a null
Session
reference, and will throw the Exception
you get.
The you do this
List<Period> periods = _periodDAO.getPeriods(team);
Let's say the List
contains a Period
object with id 42
, so the if
in
if (!periods.contains(defaultPeriod)) {
defaultPeriod = periods.get(periods.size() - 1);
}
doesn't get executed. Although the equals()
returns true
(contains()
also returns true
and becomes false
because of !
), the objects are not the same. The on in the List
has an attached (non-null) Session
, so that one can be initialized. But yours, the one held by defaultPeriod
cannot.