JPA query for getting the whole tree

前端 未结 2 1632
感情败类
感情败类 2021-01-12 03:01

I have a class which models all categories and they can be ordered hierarchically.

@Entity
@Table(name=\"categories\")
public class Category {
    @Id
    @G         


        
相关标签:
2条回答
  • 2021-01-12 03:24

    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.

    0 讨论(0)
  • 2021-01-12 03:47

    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.

    0 讨论(0)
提交回复
热议问题