2015-12-10 18 views
5

in letzter Zeit experimentierte ich ein wenig mit JPA zu versuchen, das gesamte Framework ein wenig mehr zu verstehen. Ich benutze Eclipselink als JPA-Anbieter.JPA-Aufruf-Methode auf lazy (nicht geladen) Sammlung, wenn gelöst nicht funktioniert wie erwartet in Eclipselink

Ich habe zwei Entitäten mit einer Beziehung (eine Person hat viele Adressen), die faul geladen ist.

Wenn ich eine Personenentität lade, entferne sie und versuche dann auf die (nicht geladenen) Adressen zuzugreifen ... es wirkt wie ein Zauber. Beim Debuggen kann ich sehen, dass eine Datenbankabfrage ausgeführt wird, wenn die size() Methode der Adressliste ausgeführt wird.

Ich verstehe nicht, warum das funktioniert. Ich würde eine Art Ausnahme erwarten. Ich habe in den letzten Tagen einiges über jpa und Ähnliches gelesen (ich z. B. this link), aber alles wies mich auf die Schlussfolgerung hin, dass es nicht funktionieren sollte.

Kann jemand bitte erklären, warum das funktioniert?

@Stateless 
public class Test { 
    @PersistenceContext(unitName="TestPU") EntityManager em; 

    public void test() { 
     Person person = em.find(Person.class, 1); 

     System.out.println(person); 

     System.out.println("em.contains(person): " + em.contains(person); 

     em.detach(person); 

     System.out.println("em.contains(person): " + em.contains(person); 

     person.getAddresses().size(); 

     System.out.println("em.contains(person): " + em.contains(person); 

     System.out.println(person); 

    } 
} 

Das resultierende Protokoll

DEBUG: SELECT ... from PERSON WHERE (id = ?) 
Person{id=1, name=Test, addresses={IndirectList: not instantiated}} 
em.contains(person): true 
em.contains(person): false 
DEBUG: SELECT ... FROM ADDRESSES where (address_fk = ?) 
em.contains(person): false 
Person{id=1, name=Test, addresses={[Address{id=10, city=Testcity}]}} 
+3

weil sie mit EclipseLink die Objekte nicht wirklich "loslösen", wie es die JPA-Spezifikation beabsichtigt (dh die Verbindung zur DB trennt), so dass sie die Verbindungsinformationen behalten ... daher ruft sie das Feld ab (obwohl es nicht sollte) wenn wirklich "abgelöst"). Wenn Sie dieselbe Operation für andere JPA-Anbieter ausgeführt haben, würden sie normalerweise eine Ausnahme auslösen, wenn ein Feld nicht getrennt wurde. –

+0

Sie können überprüfen, ob die Entität durch Aufrufen von [em.contains] (http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#contains%28java.lang.Object) ordnungsgemäß getrennt wurde % 29) –

Antwort

1

Wie beschrieben here detach entfernt die Entity aus dem Kontext wäre, so dass es nicht mehr verwaltet wird. Da der Kontext dennoch verfügbar ist, können bei Bedarf noch nicht getriggerte faule Sammlungen abgerufen werden, und EclipseLink hielt dies für wertvoller als eine Ausnahme auszulösen. Dies wird als eine Funktion von EclipseLink betrachtet und ist durch die JPA-Spezifikation erlaubt, obwohl andere Anbieter das Verhalten nicht standardmäßig aktivieren.

+0

Danke für die Klarstellung. Obwohl ich nicht sicher bin, dass die JPA-Spezifikation dieses Verhalten zulässt. Ich bin kein Experte im Lesen von Spezifikationen, aber soweit ich verstehe, lässt das folgende Zitat dieses Verhalten nicht zu: "Der verfügbare Zustand einer assoziierten Instanz KANN NUR auf zugegriffen werden, wenn die zugehörige Instanz verfügbar ist." (JSR 338 Abschnitt 3.2. 7 getrennte Einheiten) – Filou

+0

Das besagt, dass das Verhalten nicht definiert ist, nicht dass es eine Ausnahme erfordert und EclipseLink die Referenzimplementierung für die Spezifikation ist. Es ist nicht sicher, später auf die Beziehung zuzugreifen, da Entitäten jederzeit serialisiert werden können, wodurch die Verbindung zum Kontext unterbrochen wird (selbst wenn sie noch offen ist). – Chris

+0

Sie haben Recht, es ist nicht verboten. Es gibt kein _must not_. Ich muss mich nur ein bisschen mehr an das Lesen von Spezifikationen gewöhnen. Danke nochmal für die Klarstellung! – Filou