2017-01-26 3 views
0

Ich baue eine Baumstruktur, die in der Datenbank gespeichert ist. Die Beziehung basiert auf den Feldern id, parend_id in der Datenbanktabelle. Ich verwende Federdaten und überwintern.Fetchtype.LAZY mit gleicher Entität

Für den Zugriff auf die Baumstruktur baue ich eine Entitätsklasse "Node" und ein "NodeRepository". Die Entitätsklasse hat ein Attribut "Kinder", das eine @ OneToMany-Beziehung zu sich selbst hat.

Das Abrufen der Knoten ist kein Problem. Aber das Abrufen der Kinder ist ein Problem, weil es sich außerhalb einer Transaktionsumgebung ("versäumt, eine Sammlung von Rollen langsam zu initialisieren") befindet.

Ich änderte den Fetchmode zu eifrig. Aber das ist auch ein Problem wegen der Beziehung zu sich selbst, es endete damit, dass die gesamte Baumstruktur abgerufen wurde.

Also, was ist die beste Methode in diesem Fall, um die Wiedereingliederung der Kinder auf der einen Seite leicht zu halten und nicht die ganze Struktur auf der anderen Seite zu holen?

+0

Ich habe keine Zeit, um eine vollständige Antwort zu schreiben/eine doppelte Frage nachschlagen, aber ich würde Ihnen raten, in * Entity-Graphen *, eine JPA 2.1-Funktion zu lesen, die zuverlässig mit bedingten Laden von faulen Eigenschaften umzugehen. – Gimby

+0

Ich habe schon @NamedEntityGraph angeschaut, aber ich denke, dass es mein Problem wegen der rekursiven Beziehung nicht lösen wird. An welchem ​​Punkt muss ich den Hinweis platzieren, um die Kinder zu bekommen? – st4rbuck

+0

Ich habe nie verstanden, warum Hibernate die Spezifikation erzwingt, so dass faule Sammlungen nicht auf getrennte Entitäten geladen werden können. Persönlich ist dies einer der Gründe, warum ich EclipseLink bevorzuge, denn obwohl EclipseLink die JPA-Referenzimplementierung ist, haben sie sich entschieden, diese Regel zu brechen, weil es keinen Sinn ergibt und für den Entwickler ein absoluter Schmerz ist. –

Antwort

0

Es hängt wahrscheinlich von der Provider-Implementierung ab. In der Regel wird die Children-Sammlung jedoch initialisiert, wenn Sie die Sammlung in irgendeiner Weise verwenden. Eine übliche Methode ist also, children.size() anzurufen, bevor Sie aus der Transaktion aussteigen und das Ergebnis wegwerfen.

0

Sie können weiterhin den Typ "Lazy Fetch" verwenden und sicherstellen, dass die Sitzung nicht geschlossen wurde, als alle untergeordneten Elemente abgerufen wurden. Sie können einfach do:

Session session = sessionFactory.openSession(); 
// fetch all required Nodes & all their children by using the same session object 
session.close(); 
+0

welche Sitzung? OP bezieht sich auf JPA (in Tags) –

+0

Ich habe versucht, eine Sitzung von meinem EntityManagerFactory mit "SessionFactory session_factory = emf.unwrap (SessionFactory.class);" und öffne dann eine neue Sitzung von der Sitzungsfabrik, bevor ich auf die Kinder zugreife. Ich habe nicht gearbeitet. Ich habe die "fehlgeschlagen, um eine Sammlung von Rollen" Ausnahmen zu initialisieren. – st4rbuck

+0

Sie müssen Knoten-Entitäten zuerst mit Ihrem neu erstellten Sitzungsobjekt holen und anschließend eine Liste von Kindern abrufen. Alternativ können Sie, wenn Sie spring in Ihrem Projekt verwenden, einfach die Methode markieren, in der Sie die Children-Liste mit @Transactional Annotation abrufen, wodurch sichergestellt wird, dass die Transaktion bis zum Ende des laufenden Threads geöffnet bleibt. –

0

Wenn Sie eine weitere Beziehung in Ihrem Unternehmen eifrig haben müssen Sie die Anmerkung @Fetch(FetchMode.SELECT) in den anderen eagers umfassen.

Einchecken von official documentation jeder der verfügbaren Typer im Fetchmode.

0

Ich denke, ich habe eine Lösung, die meinen Bedürfnissen entspricht.

Zuerst habe ich eine benutzerdefinierte Schnittstelle definiert, die meine NodeRepository-Schnittstelle erweitert, ihr eine zusätzliche Methode "findOneWithChildrenInit" gibt und sie implementiert hat.

public interface NodeRepositoryCustom { 

    public Node findOneWithChildrenInit(Long id); 

} 

public class NodeRepositoryImpl implements NodeRepositoryCustom { 

    @Autowired 
    NodeRepository repo; 

    @Override 
    @Transactional 
    public Node findOneWithChildrenInit(Long id) { 
     Node node = repo.findOne(id); 
     node.getChildren().size(); 
     return node; 
    } 

} 

So kann ich entscheiden. Wenn ich die Kinder nicht brauche, kann ich einfach findOne() anrufen. Dann brauche ich sie, ich rufe findOneWithChildrenInit() auf.

Verwandte Themen