# Objekt mit lazy-verbindung komplettieren



## sparrow (20. Mrz 2008)

Hallo Forum,

ich habe ein Objekt mit einem enthaltenen Set. Das ist soweit kein Problem. Nachgeladen wird bei Bedarf über Lazy-Loading. 
Gibt es eine Möglichkeit das Objekt auch so zu laden, dass es zwischenzeitlich nich über Lazy-Loading vervollständigt werden muss? Quasi ein erzwungenes Eager für ein einziges Laden?


Gruß und Dank im Vorraus
Sparrow


----------



## SlaterB (20. Mrz 2008)

Hibernate.initialze(object)


----------



## Guest (20. Mrz 2008)

Schreib eine passende Query dazu.
z.B.
	
	
	
	





```
SELECT p FROM Person p JOIN FETCH p.adressen WHERE p.id = :personId
```


----------



## sparrow (20. Mrz 2008)

Also wenn das wirklich so einfach geht wie SlaterB sagt, das wäre ja fantastisch.
Angenommen man hat eine Pizza mit einer Liste von Belagen, dann könnte man mit Hibernate.initialize(Pizza) dafür sorgen, dass das Objekt inklusive der Liste der Belage aus der Datenbank geholt wird? Lazy Loading ist dann nicht mehr nötig?

Die Lösung vom Gast wirkt leider sehr statisch.

Gruß
Sparrow


----------



## semi (20. Mrz 2008)

Hi, Gast hier. 
Was meinst du mit statisch? Wenn das Eager-Loading eher Ausnahme ist, dann ist eine extra Query die übliche 
Vorgehensweise. Funktioniert auch mit anderen JPA-Implementierungen, nicht nur mit Hibernate.

Übrigens, sowas wie Hibernate.initialize(object) impliziert, dass es bereits eine Instanz des Objektes gibt.
Was auch immer es tut, du hast bei dem Aufruf zusätzliche Queries. Gleiches kannst du auch erreichen, 
wenn du direkt den Getter für die Collection aufrufst. Wenn ich dich richtig verstanden habe, willst du 
gerade dies vermeiden und stattdessen alles auf einen Schlag lesen.


----------



## sparrow (21. Mrz 2008)

Huhu semi 

Du hast Recht, ich möchte ein Objekt so erhalten, dass ich damit session-unabhängig arbeiten kann. Zum Beispiel um es zu serialisieren.

Wenn ich das richtig verstehe gibt es 3 Möglichkeiten:

1) Hibernate.initialize(Object) welches die aber ein bereits vorhandenes Objekt voraussetzt

2) Dein Vorschlag mit der Query

3) Das Aufrufen aller getter für die Verbundenen Listen


Mit statisch meine ich, dass man dann alle Listen manuell mit der Abfrage aufrufen muss, während ja 1) das alles automatisch macht, richtig?


Vielen Dank für deine Hilfe!


----------



## semi (21. Mrz 2008)

Ich weiss nicht, was Hibernate.initialize macht, habe es noch nie verwendet und auch nicht nachgeschaut,
aber es erspart dir vermutlich die Getter-Aufrufe. Somit ist 1) und 3) das gleiche, wobei 1) weniger Getippe 
bedeutet. Probiere es aus, dann weisst du mehr.

Wie sieht das Ergebnis aus, wenn du es, ohne die Daten nachzuladen, direkt serialisierst?
z.B. sowas mal zum Test und person2 betrachten. Beobachte dabei, ob die Daten beim Serialisieren 
nachgeladen werden und vor allem von welchem Typ sie sind.
	
	
	
	





```
Person person = findById(1); // Das Objekt normal laden

ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(person);
out.close();
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));

Person person2 = (Person)in.readObject();
```


----------



## sparrow (21. Mrz 2008)

Wenn ein serialisiertes Objekt wieder geladen wird kommt es zu einer LazyInitializationException wenn ich versuche auf die Liste zuzugreifen. Es funktioniert wenn ich das Objekt wieder in eine Session einhänge, aber genau das will ich ja nicht.


----------



## semi (22. Mrz 2008)

Aha, dann wurden die Proxies serialisiert. Die kannst du clientseitig kaum gebrauchen. Ausserdem müsste 
die Implementierung cliientseitig auch bekannt sein. Klartext: Hibernate clientseitig in Classpath. 
Das ist nicht so sexy.  Passiert Gleiches bei Hibernate.initialize(...)? Wenn ja, dann bleibt dir nichts anderes 
übrig, als eine extra Query. Wenn das auch ein Problem ist, dann DTOs.


----------



## maki (22. Mrz 2008)

initialize sorgt nur dafür, dass nur die angegebene Property/Collection initialisiert wird, nicht das ganze Objekt, dafür ist die LEFT JOIN FETCH besser geeignet.

Man braucht nicht zu DTOs zu greifen (und damit einen Rückschritt in der Entwicklung machen).

Man muss nur dafür sorgen, dass die Objekte je nach Anwendungsfall(use case) "richtig" geladen werden.
Brauche ich nicht den kompletten Objektgraphen, sondern will zB. nur eine Liste von Objekten anzeigen in der nur die als EAGER gemappte Attribute vorkommen, reichen die Proxies und die Performance geht nicht in den Keller.
Brauche ich den kompletten Objektgraphen, muss ich dafür sorgen, dass Hibernate nicht faul ist  am besten mit der von semi vorgestellten Syntax.

Das schwierige dabei?
Die einzelnen Use Cases zu identifizieren und entsprechende Methoden in der Business Schicht implementieren.


----------



## SlaterB (22. Mrz 2008)

> initialize sorgt nur dafür, dass nur die angegebene Property/Collection initialisiert wird, nicht das ganze Objekt

hmm, kannst du das näher erläutern, 
wenn man doch
Hibernate.initialize(object);
aufruft, also nur das Objekt übergibt?

wie genau bezeichnest du diese Aktion wenn du 'initialisiert das ganze Objekt' explizit ausschließt?


----------



## maki (22. Mrz 2008)

Aus der API Doc zu initialize: http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Hibernate.html#initialize(java.lang.Object)



> Force initialization of a proxy or persistent collection.
> 
> Note: This only ensures intialization of a proxy object or collection; it is not guaranteed that the elements INSIDE the collection will be initialized/materialized.


Soll heissen, wenn ich von meiner Entität eine property übergebe, welche eine Collection ist:

```
MyEntity myEntity = ....

initialize(myEntity.getPropertyWhichIsACollection);
```
Sorgt initialize dafür, dass die Collection geladen wird, aber nicht notwendigerweise auch die Objekte/Elemente in der Collection initialisiert werden, könnte nur eine Collection von Proxies dabei rauskommen... da müsste man für jedes Element der Collection initialize aufrufen.
Bei initialize wird nicht notwendigerweise der gesamte Objektgrpah initialisiert, können immer noch Proxies dabeisein.


----------



## SlaterB (22. Mrz 2008)

dass die referenzierten Objekte nicht auch rekursiv initalisiert werden ist doch klar,
sonst hätte man ja meist mit einem Aufruf die halbe Datenbank geladen 

aber ich frage mich immer noch was gegen 'initialisiert das ganze Objekt' spricht,

nehmen wir mal ein Objekt A
mit lazy referenzierten Objekten B, C, D 
sowie lazy referenzierten Listen von Objekten E und F

klar kann man wenn man will nur die Liste für E übergeben,
aber das ist ja nicht die Frage,
sondern man ruft 
Hibernat.initialize(Object A);
auf,

dann werden doch wohl die Objekte B, C, D sowie alle referenzierten E und F geladen, oder?
habs noch nicht wirklich richtig ausprobiert, aber so bisher verstanden,

die zusätzlich geladenen Objekte sind natürlich relativ leer,
deren lazy Objekte werden wie gesagt nicht rekursiv geladen,
da ja sonst Armageddon


----------



## maki (22. Mrz 2008)

> aber ich frage mich immer noch was gegen 'initialisiert das ganze Objekt' spricht,


Nun, das kommt darauf an, wie man "initialisiert" definiert 



> dann werden doch wohl die Objekte B, C, D sowie alle referenzierten E und F geladen, oder?
> habs noch nicht wirklich richtig ausprobiert, aber so bisher verstanden,


Ja, sehe ich auch so.

Manchmal braucht man wirklich das armageddon (das ganze Objekt samt aller "unterobjekte", keine Proxies), meistens jedoch nur das faule Objekt mit den Proxies.

"Armageddon" lässt sich auch durch fetchtype=eager/lazy=false in den Mappings auslösen, manchmal ist es richtig, meist Verschwendung.

Wir haben in unseren Session EJBs jeweils zwei Arten Methoden:
Diejenigen, die auch Proxies liefern, und diejeniegen, die nie Proxies liefern.
Letztere heissen load und erwarten eine ID als Parameter, liefern nur ein einziges Objekt, dafür aber alles echt.
Die anderen, hiessen irgendwas mit "List", erwarten Criterias, oder andere Suchkriterien, leifern aber keine 100% echten Objekte, sondern nur das Oberste ist initialisiert, der rest sind oft(aber nicht immer) Proxies.

Während das "Armageddon" für normale Objekte meist "nur" aus mieser Performance besteht, kann es für große Objekte, zB. Dateien die als BLOB persistiert werden, sogar zum Crash führen.
5000 Dateien mit je 20MB auf einmal in den RAM zu laden ist sicherlich keine gute Idee.


----------

