web-dev-qa-db-fra.com

Hibernate n'a pas pu initialiser le proxy - pas de session

Mon code récupère toutes les informations relatives à l'utilisateur:

SessionFactory sessionFactory = HibernateUtilities.configureSessionFactory();
Session session = sessionFactory.openSession();
UserDetails ud = null;
Set<Address> userAddress = null;

try {
    session.beginTransaction();
    ud = (UserDetails) session.get(UserDetails.class, 1);
    userAddress = ud.getAddresses();
    session.getTransaction().commit();
} catch (HibernateException e) {
    e.printStackTrace();
    session.getTransaction().rollback();
} finally {
    session.close();
}

System.out.println(ud.getName());

for(Address addr: userAddress){
    System.out.println("State " + addr.getState());
}

La ud.getAddresses() renvoie simplement un ensemble de Addresses de l'utilisateur.

Ma question est: pourquoi l'objet ud a-t-il toujours sa valeur (par exemple, nom) même si la session est déjà fermée? getAddresses() est une variable d'instance de la classe UserDetails. Mais pourquoi ne puis-je pas récupérer sa valeur mais je peux récupérer des variables d'instance régulières de la classe UserDetails?

ud.getAddresses() est un @EmbeddedCollection.

13
KyelJmD
userAddress = ud.getAddresses();
session.getTransaction().commit();
for(Address addr: userAddress) {

La documentation de mise en veille prolongée pour travailler avec des associations paresseuses appelle clairement ce type d'accès comme une erreur. Vous ne pouvez interagir avec des objets associés paresseusement que pendant que la session est encore ouverte. Cette partie de la documentation fournit également des alternatives pour accéder à ces membres paresseusement associés d'un objet et nous préférons spécifier le mode de récupération comme JOIN dans les critères utilisés, dans nos applications.

16
Vikdor

J'ai rencontré le même problème dans JPA/Hibernate, et il y a 2 façons de résoudre ce problème:

1/Éteignez le LAZY par défaut, comme suit:

@Entity
@Proxy(lazy = false)
public class Project {
...
}  

Bien sûr, cette méthode n'est pas recommandée en raison du problème de performances, vous pouvez donc passer à la deuxième méthode.

2/Vous pouvez mettre @Transactional au début de votre méthode, cela peut vous aider à rester la session, ou une autre compréhension, ça passe le devoir de session à Hibernate, comme suit:

@Test
@Transactional
public void testSaveGroup() {
    Department g = new Department();
    g.setName("XDG");
    assertNull(g.getId());
    this.groupRepo.save(g);
    assertNotNull(g.getId());
    System.out.println(g.getId());
    Project dummyPrj = new Project(123L, "KSTA", new Date(), "NEW", "Helm AG", g);
    this.projectRepo.save(dummyPrj);
    // verify
    List<Department> lst = this.groupRepo.findAll();
    Project savedPrj = this.projectRepo.getOne(123L);
    Assert.assertEquals("XDG", savedPrj.getGroup().getName());
}

Ma réponse est en retard, mais j'espère aider quelqu'un d'autre :)

19
doannx

Toutes les propriétés primitives des classes sont chargées immédiatement, elles ne peuvent pas être paresseuses à moins que vous n'utilisiez des améliorations de bytecode. Seules de vraies associations comme votre collection peuvent être paresseuses.

4