2013-09-10 1 views
8

Сегодня я столкнулся с очередной проблемой в спящем режиме:Ленивый инициализация коллекции проваливается в спящем режиме

Моего метод:

@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; 
} 

Метод initializeIssues:

public void initializeIssues(Period period) { 
    if (period.getIssues() != null) { 
     Hibernate.initialize(period.getIssues()); 
    } 
} 

я получаю исключение, если коллекция периодов содержит 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) 

Но если удалить несколько строк и метод изменения в

@Transactional  
public Period getDefault(Team team) { 
    Period defaultPeriod = team.getDefaultPeriod(); 
    _periodDAO.initializeIssues(defaultPeriod); 
    return defaultPeriod; 
} 

Он отлично работает.

Я отлаживал первый пример, а сеанс спящего режима не закрывался в течение всего метода.

Как я понимаю, если загруженный объект (один элемент в периоды) в сессии имеет коллекцию, которая связана с активной сессии и существовавшей до объекта (defaultPeriod) также имеет ту же ассоциацию - это (defaultPeriod) потеряет его ассоциации.

Это правда? Кто еще столкнулся с такой же проблемой?

Благодарим за ответы.

ответ

13

Предположительно, ваш аргумент Team исходит из другой транзакции и другого спящего режима Session.

Когда @Transactional метод возвращает значение, то TransactionManager закрывает Session, который делает некоторую очистку и сбрасывает (наборы к null) в Session поле всех PersistentCollection экземпляров. Ваш defaultPeriod имеет один из них в своем поле issues.

в Hibernate Hibernate.initialize() заставляет инициализацию ленивого PersistentCollection, но имеет следующий код (звонки AbstractPersistentCollection#forceInitialization())

if (session == null) { 
     throw new HibernateException("collection is not associated with any session"); 
    } 

Если вы планируете использовать issues коллекции за пределами первоначального @Transactional метода (код, который производит Team), вам необходимо загрузить базовые объекты. Либо замените его на загрузку EAGER, либо сделайте то, что вы делаете, с Hibernate.initialize().

Другое решение состоит в том, чтобы сделать Session дольше, чем просто длина первого @Transactional, но у меня нет деталей для этого. Быстрый поиск Google или SO должен вызывать некоторые варианты.


Это то, что происходит

Period defaultPeriod = team.getDefaultPeriod(); 

получает Period объект с идентификатором (напр.) 42.Потому что это произошло в другом Session, который с тех пор был закрыт, issues - это PersistentCollection, который имеет ссылку , и будет выталкивать Exception, который вы получаете.

вы это

List<Period> periods = _periodDAO.getPeriods(team); 

Скажем List содержит Period объект с идентификатором 42, так if в

if (!periods.contains(defaultPeriod)) { 
     defaultPeriod = periods.get(periods.size() - 1); 
    } 

не получает казнены. Хотя equals() возвращает true (также возвращает true и становится false из-за !), объекты не совпадают. Включение в List имеет прикрепленный (не нулевой) Session, так что его можно инициализировать. Но ваш, тот, который держится defaultPeriod, не может.

+0

Спасибо! Но ** TransactionManager ** устанавливает нулевое поле ** Session ** для * issues * in * defaultPeriod * только в том случае, если * периоды * содержат * defaultPeriod *, если нет - * issues * будет хорошо инициализироваться. – Alexz

+0

@OleksandrZ Я бы посмотрел на ваш метод 'equals()' для сравнения экземпляров 'Period'. Хотя 'Periods' может содержать его, тот, который находится в коллекции, привязан к' Session', а другой - снаружи. –

+0

** равно ** метод очень прост и основан на сравнении ** Period ** id. Я могу инициализировать проблемы ** defaultPeriod ** только в том случае, если я снова не возвращаюсь из db этого объекта, поэтому, если я изменю код и добавлю ** Period defaultPeriod2 = _periodDAO.get (defaultPeriod.getId()); ** вместо извлечение ** периодов **, проблемы снова не будут инициализированы. Благодарю. – Alexz

 Смежные вопросы

  • Нет связанных вопросов^_^