/ / L'initialisation de la collection paresseuse échoue en mode hibernation

L'initialisation de la collection paresseuse échoue dans l'hibernation - java, hibernate, collections, initialisation différée

Aujourd'hui, j'ai fait face au prochain problème en veille prolongée:

Ma méthode:

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

Méthode initializeIssues:

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

Je reçois une exception si collection périodes contient 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)

Mais si je supprime quelques lignes et que je change de méthode,

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

Ça fonctionne bien.

J'ai débogué le premier exemple et la session de veille prolongée ne se ferme pas pendant toute la méthode.

Si je comprends bien, si objet chargé (un élément dans périodes) en session a une collection qui est associée à une session active et à un objet avant existant (defaultPeriod) a également la même association - il (defaultPeriod) va perdre son association.

Est-ce la vérité? Qui d'autre est confronté au même problème?

Merci pour les réponses.

Réponses:

13 pour la réponse № 1

Vraisemblablement, votre Team l'argument vient d'une autre transaction et d'un autre Hibernate Session.

Lorsqu'un @Transactional la méthode retourne, le TransactionManager ferme le Session qui fait un peu de nettoyage et désactive (définit à null) la Session domaine de tous PersistentCollection les instances. Votre defaultPeriod a l'un d'entre eux dans son issues champ.

Hibernate "s Hibernate.initialize() force l'initialisation d'un paresseux PersistentCollection, mais a le code suivant (appelle AbstractPersistentCollection#forceInitialization())

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

Si vous prévoyez d’utiliser le issues collection en dehors de l'original @Transactional méthode (le code qui produit Team), vous devez charger les objets sous-jacents. Changez-le en chargement EAGER ou faites ce que vous faites avec Hibernate.initialize().

Une autre solution consiste à rendre le Session durer plus longtemps que juste la longueur de la première @Transactional, mais je n’ai pas de détails à ce sujet. Une recherche rapide dans Google ou SO devrait faire apparaître certaines options.


C'est ce qui se passe

Period defaultPeriod = team.getDefaultPeriod();

Obtient un Period objet avec id (ex.) 42. Parce que c'est arrivé dans un autre Session qui a depuis été fermé, le issues est un PersistentCollection qui a un null Session référence, et jettera le Exception vous recevez.

Le tu fais cela

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

Disons le List contient un Period objet avec identifiant 42, alors le if dans

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

ne pas "être exécuté. Bien que le equals() résultats true (contains() retourne aussi true et devient false en raison de !), les objets ne sont pas les mêmes. Le dans le List a un attaché (non nul) Session, afin que l'on puisse être initialisé. Mais le tien, celui tenu par defaultPeriod ne peux pas.