Frage

habe ich ein Problem mit Hibernate und der LazyInitializationException. Ich suchte und eine Menge Antworten zu finden, aber ich kann sie nicht mein Problem verwenden zu lösen, weil ich zu sagen habe, ich bin neu in dem Ruhezustand.

Ich betreiben JUnit-Tests, bei dem Fehler um dies ein:

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

Die letzte Zeile dargestellt:

testProject.getPersons().add(person);

wirft diesen Fehler:

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

Person und Projekt ist bidirektional 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>();

Also, was ist das Problem?

War es hilfreich?

Lösung

Das Problem besteht darin, dass die Kollektion ist standardmäßig träge geladen. Dies bedeutet, dass sie tatsächlich aus der Datenbank geladen werden wont, bis sie zugegriffen wird. Um es zu laden benötigen Sie eine aktive Sitzung / Transaktion.

Der einfache Ausweg ist es FethType.EAGER zu ändern, die stellt sicher, dass die Sammlung sofort aufgefüllt wird.

- update -

Ich habe das gleiche Problem hat vor kurzem und ich am Ende meines eigentlichen Dienst zu modifizieren mit dieser Art der Sache zu befassen. Deklarieren Sie eine addPerson Methode in Ihrer ProjectService Klasse.

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

Andere Tipps

Setzen Sie Ihren Code innerhalb einer Transaktion - das Problem lösen wird für Sie

Können Sie versuchen

person.getProjects().Add(testProject)

statt

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

Sie sollten, da sonst tun dies werden Sie eine Hibernate verwaltete Sammlung weggeblasen würden.

Von Hibernate Referenz:

Standardmäßig verwendet Hibernate3 faul wählen Abrufen für Sammlungen und faul Proxy-Abrufen für Verbände einwertig. Diese Standardwerte sind sinnvoll für die meisten Verbände in den meisten Anwendungen.

Wenn Sie hibernate.default_batch_fetch_size gesetzt ist, wird Hibernate verwenden, um das Batch holt Optimierung für faulen Abruf. Diese Optimierung kann auch auf einer detaillierteren Ebene aktiviert werden.

Bitte beachten Sie, dass der Zugang zu einer faulen Vereinigung außerhalb des Kontexts einer offenen Hibernate-Session zu einer Ausnahme führen. Zum Beispiel:

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!

Da die Sammlung von Berechtigungen nicht initialisiert wurde, wenn die Sitzung geschlossen wurde, wird die Sammlung nicht in der Lage sein, seinen Zustand zu laden. Hibernate unterstützt nicht faul Initialisierung für freistehende Objekte. Dies kann durch Verschieben des Codes festgelegt werden, die aus der Sammlung liest bis kurz vor der Transaktion festgeschrieben wird.

Alternativ können Sie auch eine nicht faul Sammlung oder Vereinigung verwenden, durch faul = „false“ für die Assoziationskartierung angeben. Es ist jedoch beabsichtigt, dass die verzögerte Initialisierung für fast alle Sammlungen und Verbänden verwendet werden. Wenn Sie zu viele Nicht-faul Vereinigungen in Ihrem Objektmodell definieren, Hibernate wird die gesamte Datenbank in den Speicher in jeder Transaktion holen.

Auf der anderen Seite, können Sie fetching beitreten, die von Natur aus nicht-faul ist, statt wählt Abrufen in einer bestimmten Transaktion. Wir werden nun erklären, wie das Abrufen Strategie anpassen. In Hibernate3, eine Strategie holen die Mechanismen für die Auswahl sind identisch für einwertig Verbände und Sammlungen.

So Sie die Sitzung nach dem Zugriff auf die Sammlung schließen haben!

Statt:

service.addPerson(person);

testProject.getPersons().add(person);

Ich glaube, Sie haben sollte:

testProject.getPersons().add(person);
service.addPerson(person);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top