Question

J'ai un problème avec Hibernate et le LazyInitializationException. J'ai cherché et trouver beaucoup de réponses, mais je ne peux pas les utiliser pour résoudre mon problème, parce que je dois dire, je suis nouveau hiberner.

Je lance des tests JUnit, en cas de l'erreur celui-ci:

@Test
public void testAddPerson() {
    Set<Person> persons = service.getAllPersons();

    // create new person
    Person person = new Person();
    person.setEmail("john@doe.com");
    Project testProject = serviceProj.findProjectById(1);

    HashSet<Project> lister = new HashSet<Project>();
    lister.add(testProject);
    person.setProjects(lister);
    service.addPerson(person);

    testProject.getPersons().add(person);
    ...
}

La dernière ligne affichée:

testProject.getPersons().add(person);

lance cette erreur:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.doe.john.domain.Project.persons, no session or session was closed

personne et le projet sont n bidirectionnel: m:

Person.java :

@ManyToMany(mappedBy="persons")
private Set<Project> projects = new HashSet<Project>();

Project.java :

@ManyToMany
@JoinTable(name = "Project_Person",
    joinColumns = {@JoinColumn(name="project_id", referencedColumnName="id")},
    inverseJoinColumns = {@JoinColumn(name="person_id", referencedColumnName="id")}
)
private Set<Person> persons = new HashSet<Person>();

Alors, quel est le problème?

Était-ce utile?

La solution

Le problème est que par défaut, la collection est chargée paresseusement. Cela signifie qu'il ne sera pas en chargé de la base de données en fait jusqu'à ce qu'il soit en cours d'accès. Pour le charger, vous aurez besoin d'une session active / transaction.

out moyen facile est de changer à FethType.EAGER qui veille à ce que la collection est directement peuplée loin.

- mise à jour -

J'ai récemment eu le même problème et je fini par modifier mon service réel pour faire face à ce genre de chose. Déclarer une méthode addPerson dans votre classe ProjectService.

public void addPersonTo(Project project, Person person)
{
  project = em.merge(project); //EntityManager, not sure what you are using but you get the idea hopefully
  project.addPerson(person);
}

Autres conseils

Mettez votre code dans une transaction - cela résoudra le problème pour vous

Pouvez-vous essayer

person.getProjects().Add(testProject)

au lieu de

HashSet<Project> lister = new HashSet<Project>();
lister.add(testProject);
person.setProjects(lister);

Vous devriez faire cela puisque vous auriez autrement souffler loin d'une mise en veille prolongée collection gérée.

De référence Mise en veille prolongée:

Par défaut, Hibernate3 utilise select pour les collections fetching paresseux et proxy pour les associations allant chercher paresseux univoques. Ces valeurs par défaut de sens pour la plupart des associations dans la plupart des applications.

Si vous définissez hibernate.default_batch_fetch_size, Hibernate utilisera le chargement par lot optimisation pour le chargement paresseux. Cette optimisation peut également être activée à un niveau plus granulaire.

S'il vous plaît noter que l'accès à un extérieur d'association paresseuse du contexte d'une session hibernate ouverte, entraînera une exception. Par exemple:

s = sessions.openSession();
Transaction tx = s.beginTransaction();

User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();

tx.commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!

Depuis la collecte des autorisations n'a pas été initialisé lors de la session a été fermée, la collection ne sera pas en mesure de charger son état. Hibernate ne supporte pas l'initialisation paresseuse pour des objets détachés. Cela peut être corrigé en déplaçant le code qui se lit de la collection avant la transaction est validée.

Vous pouvez utiliser une collection non paresseux ou d'une association, en spécifiant = paresseux « false » pour le mappage d'association. Toutefois, il est prévu que l'initialisation paresseuse être utilisé pour presque toutes les collections et les associations. Si vous définissez trop d'associations non-paresseux dans votre modèle objet, Hibernate va chercher la base de données en mémoire à chaque transaction.

Par contre, vous pouvez utiliser jointure, qui est non paresseux par nature, au lieu de select dans une transaction donnée. Nous allons maintenant expliquer comment personnaliser la stratégie de récupération. En Hibernate3, les mécanismes de choix d'une stratégie de chargement sont identiques associations univoques et collections.

Vous devez fermer la session après avoir accédé à la collection!

Au lieu de:

service.addPerson(person);

testProject.getPersons().add(person);

Je pense que vous devriez avoir:

testProject.getPersons().add(person);
service.addPerson(person);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top