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.
The right way to fix a LazyInitializationException is to fetch all required associations within your service layer. The best option for that is to load the entity with all required associations in one query.
LazyInitializer is a Hibernate component that helps to generate proxy objects for Entities and can also be used to fetch the underlying entities of these proxy objects.
Class LazyInitializationExceptionIndicates an attempt to access not-yet-fetched data outside of a session context. For example, when an uninitialized proxy or collection is accessed after the session was closed.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With