Ich weiß, dass dies immer wieder diskutiert wurde (ich habe mehrere eigene Implementierungen in dieser Angelegenheit), vielleicht ist das ein Teil des Grundes, den ich stelle: es gibt keine definitive Antwort (nach Stunden von Suche) und ich fühle, das ist Fang 22.JPA Hibernate Lazy Laden von Sammlungen
Meine Einstellung ist Spring Boot 1.3.6, die mit Hibernate 4.3.11 "verheiratet" ist. Ich verwende Spring Data JPA.
Ich habe eine Entität, die mehrere Sammlungen von Untereinheiten enthält, @OneToMany
und @ManyToMany
. Das ist das Vorbild - ich liebe oder hasse es nicht.
Dann habe ich eine normale CRUD UI mit einer Tabelle der Haupteinheit und einem Editor, wo der Benutzer Optionen für die Untereinheiten auswählen und die Haupteinheit speichern kann.
Die Benutzeroberfläche ist mit Vaadin gemacht und es sind Web Sockets beteiligt. Also - kein normaler Http-Tausch.
Mit den normalen Einstellungen bekomme ich die "normale" LazyInitializationException von Hibernate. Sobald die Entität in den Tabellenbildschirm geladen wurde, wird die Sitzung geschlossen. Wenn also die Sammlungen im Editor-Bildschirm aufgerufen werden, lade ich entweder die Entity vollständig neu, was die Mojo-Verwendung eines ORM oder I zunichte macht versuchen, etwas anderes:
- die Sammlungen EAGER machen (und ziehen sie sie mit mir überall hin, nicht auf die n + 1 Problem zu erwähnen, die trotz der
@Fetch(FetchMode=JOIN)
geschieht, die es nicht haben in erster Linie sein sollen) - Fügen Sie die
spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true
zu meiner Startkonfiguration, die im Grunde die gleiche wie die erste Option ist, in einen Standard umgewandelt. Nein danke. - Verwenden Sie Hibernate.initialize für die Sammlungen unmittelbar nach dem Abrufen der übergeordneten Entität (dh in der gleichen Sitzung), das ist so etwas wie programmatische EAGER-Abruf - aber es ist stark mit Hibernate gekoppelt und es speichert mir nicht die zusätzliche Abfrage (n + 1).
- abrufen Sie die Daten mit "Fetch Join" in meiner JPQL-Abfrage - außer dies kann dazu führen, dass die Ergebnismenge auf Tausende von Zeilen eskalieren (die dann im Speicher zusammengefasst werden), ganz zu schweigen von A) erfordert JPQL für ansonsten triviale Abfragen , implementiert mit einfachen Interface-Namen in Spring Data und B) wenn Sie Paginierung wollen, müssen Sie die
countingQuery
auch schreiben (ohne Join Fetch), weil Sie sonst eine schöne, klare und leicht zu debuggenorg.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
bekommen. Auch, wenn Sie „vergessen“, um diefetchType
Optionen auf den@OneToMany
oder@ManyToMany
Anmerkungen zu entfernen, erhalten Sie eine andere Haarzieh Ausnahme:org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
- erstellen Sie einen Filter nach dem Open-in-View-Muster (oder eher anti-Muster), was würde den gleichen EntityManager für alle Anfragen in der gleichen, na ja, etwas - nicht die HTTP-Sitzung abrufen, weil wir Web Sockets verwenden (oder so ziemlich alles andere, soll Hibernate nicht ein Web-ORM sein); nicht die Vaadin-Sitzung, weil ich vielleicht mehrere Servlets habe oder die gesamte Anwendung verteile; oder hör auf, Vaadin zu benutzen; kein lokaler Thread, da ich Operationen in verschiedenen Thread-Pools ausführen kann, die nicht vom lokalen Thread geerbt wurden: Dies ist wiederum nicht die Frage von Hibernate.
schließlich zu Eclipseschalt, die den vernünftigen Ansatz, einfach Anfordern der Untersammlungen haben, wenn sie in einer neuen Sitzung scheint erforderlich, eher eine lästige Pflicht als Frühlings-Boot in der Regel Angebote (mit noch mehrere Gesprächen im Hinblick auf die Notwendigkeit, die Anwendung mit dem Instrumentierungsagenten auszuführen).
Gibt es letztendlich eine hackfreie Lösung für dieses Problem?
Also im Wesentlichen, verwenden DTO? –
Nur zwischen Sicht und Controller, ja. –
Langlebige Sitzungen sind im Wesentlichen das Open-in-View-Muster, oder hatten Sie etwas anderes vor? – Deroude