Domanda

Ho un problema con Hibernate e l'LazyInitializationException. Ho cercato e trovato un sacco di risposte, ma non li possono utilizzare per risolvere il mio problema, perché ho da dire, io sono nuovo a Hibernate.

ho eseguito test JUnit, in caso di errore questo:

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

L'ultima riga indicato:

testProject.getPersons().add(person);

getta questo errore:

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

Persona e del progetto sono bidirezionali n: 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>();

Allora, qual è il problema?

È stato utile?

Soluzione

Il problema è che per default la collezione è pigramente caricato. Ciò significa che è solito in realtà essere caricato dal database finché non si accede. Al fine di caricare avrete bisogno di un attivo di sessione / transazione.

La via d'uscita più semplice è di cambiarlo a FethType.EAGER che fa in modo che la raccolta è popolata da subito.

- aggiornamento -

Recentemente ho avuto lo stesso problema e ho finito per modificare il mio servizio effettivo a che fare con questo genere di cose. Dichiarare un metodo addPerson nella 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);
}

Altri suggerimenti

inserire il codice all'interno di una transazione - questo risolverà il problema per voi

Puoi provare

person.getProjects().Add(testProject)

anziché

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

Si dovrebbe fare questo dato che altrimenti si sarebbe soffiando via una raccolta gestita hibernate.

Da riferimento hibernate:

Per impostazione predefinita, Hibernate3 utilizza fetching selezionare pigro per collezioni e procura pigri che vanno a prendere per le associazioni a valore singolo. Questi valori predefiniti senso per la maggior parte delle associazioni nella maggior parte delle applicazioni.

Se si imposta hibernate.default_batch_fetch_size, Hibernate utilizzerà il lotto prendere ottimizzazione per il recupero pigro. Questa ottimizzazione può anche essere attivata a un livello più granulare.

Si prega di essere consapevoli del fatto che l'accesso ad un'associazione di fuori pigro del contesto di una sessione Hibernate aperta si tradurrà in un'eccezione. Ad esempio:

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!

Dal momento che la raccolta delle autorizzazioni non è stata inizializzata quando la sessione è stata chiusa, la collezione non sarà in grado di caricare il suo stato. Hibernate non supporta l'inizializzazione differita per oggetti sganciati. Questo può essere risolto spostando il codice che legge dalla raccolta a poco prima che la transazione è impegnata.

In alternativa, è possibile utilizzare una raccolta o di un'associazione non-pigro, specificando = pigri "false" per la mappatura dell'associazione. Tuttavia, si prevede che l'inizializzazione pigra essere utilizzato per quasi tutte le collezioni e le associazioni. Se si definisce troppe associazioni non pigri nel modello a oggetti, Hibernate preleverà l'intero database in memoria in ogni transazione.

D'altra parte, è possibile utilizzare unire recupero, che non è pigro per natura, invece di selezionare recupero in una determinata operazione. Noi ora spiegare come personalizzare la strategia di recupero. In Hibernate3, i meccanismi per la scelta di una strategia di recupero sono identici per le associazioni a valore singolo e collezioni.

Quindi, è necessario chiudere la sessione dopo l'accesso alla collezione!

Al posto di:

service.addPerson(person);

testProject.getPersons().add(person);

Penso che si dovrebbe avere:

testProject.getPersons().add(person);
service.addPerson(person);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top