2010-04-08 12 views
8

Ich habe eine Klasse, die alle Kategorien modelliert und sie können hierarchisch angeordnet werden.JPA-Abfrage für den gesamten Baum

@Entity 
@Table(name="categories") 
public class Category { 
    @Id 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence") 
    @SequenceGenerator(name="sequence", sequenceName="categories_pk_seq", allocationSize=1) 
    @Column(name="id") 
    private Long id; 

    @Column 
    private String name; 

    @OneToOne 
    @JoinColumn(name="idfather") 
    private Category father; 

} 

Ich brauche alle Kategorien hierarchisch geordnet werden (ich meine, jeden Vater, gefolgt von seinen Kindern und Vätern auf jeder Ebene alphabetisch geordnet), wie sie zum Beispiel mit PRIOR in Orakeln gemacht werden kann. Ist es möglich, dies mit einer JPA-Abfrage (nicht eine SQL-Abfrage) zu tun?

Danke.

+1

In Ihrem Fall nehme ich an, dass Sie Eltern-Kind-Beziehung benötigen. So etwas wie @OneToMany @JoinColumn (Name = "IDFather") @OrderBy (Wert = "Name") private Liste Kinder werden Ihnen helfen. Wenn Sie dann eine Stammkategorie abrufen, wird der gesamte Baum geladen. –

+0

@dma_k Ich hatte bereits die gleiche Idee und nachdem ich wusste, dass es nicht passierbar war, versuchte ich die JPA-Abfrage auf diese Weise. – Javi

+0

Kannst du uns bitte auch den Java-Code mitteilen, der den Baum tatsächlich lädt? Ich frage mich, wie Sie JPA-Abfrage erstellen/ausführen. Ich denke auch, dass, wenn der Persistenz-Layer den Baum lädt, indem er eine Abfrage für einen Baum-Knoten ausführt, er wissen sollte, wie er Kinder abruft. Ich frage mich, wie Oracles Erweiterung "CONNECT BY PRIOR" Ihnen hier helfen kann. –

Antwort

7

Die kurze Antwort ist; Nein, es gibt keine Standardmethode, dies zu tun.

Sie müssen native SQL verwenden. Sie können den Oracle Hibernate Dialekt möglicherweise erweitern und eine Benutzerfunktion/Erweiterung hinzufügen, damit Hibernate PRIOR- oder CONNECT BY-Klauseln generiert. Dies verhindert jedoch, dass Ihre App strikt JPA- und datenbankunabhängig ist.

+0

Ich habe Oracle Hibernate Dialekt erweitert, weiß aber nicht, wie ich meine Funktionen dazu hinzufügen soll. Könnten Sie mir eine Probe vorstellen? –

+1

@RasoolGhafari Entschuldigung kann ich nicht. Es ist so lange her, dass ich mit Hibernate-Dialekten zu tun habe, dass ich mehr oder weniger alles vergessen habe, was ich wusste.Aber Sie könnten http://stackoverflow.com/questions/12346845/registering-a-sql-function-with-jpa-hibernate einen guten Ausgangspunkt finden. –

1

Zunächst einmal unter der Annahme, dass ein "Vater" in dieser Hierarchie mehr als ein Kind haben kann, dann sollte das Feld father mit @ManyToOne kommentiert werden.

Wenn Sie ein Feld haben, das alle Mitglieder eines Baums teilen, oder wenn der Baum die gesamte Tabelle enthält, dann ist möglich, es mit JPA in einer effizienten Weise zu tun, obwohl nicht durch eine einzelne JPA-Abfrage .

Sie müssen nur alle Mitglieder des Baumes Prefetch und dann durchqueren den Baum:

@Entity 
@Table(name="categories") 
public class Category { 
    @Id 
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence") 
    @SequenceGenerator(name="sequence", sequenceName="categories_pk_seq", allocationSize=1) 
    @Column(name="id") 
    private Long id; 

    @Column 
    private String name; 

    @ManyToOne 
    @JoinColumn(name="idfather") 
    private Category father; 

    @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, 
       fetch = FetchType.LAZY, 
       mappedBy = "idfather") 
    @OrderBy("name") 
    private List<Category> subCategories; 
} 

Beachten Sie die @OrderedBy Anmerkung auf dem Subkategorien Feld.

Jetzt können Sie den gesamten Baum erhalten, indem Sie zuerst alle Kategorien in eine verwirrende Liste laden, nur damit sie alle im Speicher sind, und dann den Baum durchqueren.

public List<Category> getTree() { 
    List<Category> jumbled = 
     entityManager.createQuery("from Category", Category.class).getResultList(); 

    Category root = null; 
    for(Category category : jumbled) { 
     if(category.getFather() == null) { 
      root = category; 
      break; 
     } 
    } 

    List<Category> ordered = new ArratList<Category>(); 
    ordered.add(root); 
    getTreeInner(root, ordered); 
} 

private void getTreeInner(Category father, List<Category> ordered) { 
    for(Category child : father.getSubCategories()) { 
     ordered.add(child); 
     getTreeInner(child, ordered); 
    } 
} 

Ich bin nur JPA mich jetzt lernen, damit ich etwas von entscheidender Bedeutung fehlt, aber dieser Ansatz scheint für mich zu arbeiten.

+0

Ihre Lösung wird das Problem nicht lösen. Denken Sie daran, Tausende von Kategorien und die Menge an Speicher zu haben, die es braucht, um dies zu tun, plus wir brauchen eine Lösung, um es in anderen Abfragen und Joins zu verwenden !! – azerafati

Verwandte Themen