JPA query for getting the whole tree

好久不见. 提交于 2019-12-01 04:10:01
Gareth Davis

The short answer is; no there isn't a standard way to do this.

You have to use native sql.

You may be able to extend the Oracle Hibernate Dialect and add some user function/extension to get hibernate to generate PRIOR or CONNECT BY clauses, but this will prevent your app from being strict JPA and database independent.

First of all, assuming in this hierarchy a "father" can have more than one child, then the father field should be annotated as @ManyToOne.

If you have a field that all the members of a tree share, or if the tree contains the entire table, then it is possible to do it with JPA in an efficient way, though not through a single JPA query.

You simply need to prefetch all the members of the tree, and then traverse the tree:

@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;
}

Notice the @OrderedBy annotation on the subCategories field.

Now you can get the entire tree by first loading all the categories into a jumbled list, just so that they'd all be in memory, and then traverse the tree.

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);
    }
}

I'm only learning JPA myself right now, so I may be missing something crucial, but this approach seems to work for me.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!