代码之家  ›  专栏  ›  技术社区  ›  Javi

获取整棵树的JPA查询

  •  8
  • Javi  · 技术社区  · 16 年前

    我有一个类,它为所有类别建模,并且可以按层次结构排序。

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

    我需要按层次顺序排列所有类别(我的意思是每个父亲后面跟着孩子,父亲在每个级别上按字母顺序排列),因为它们可以像Oracle中的Prior那样进行排序。是否可以使用JPA查询(而不是SQL查询)执行此操作?

    谢谢。

    2 回复  |  直到 10 年前
        1
  •  8
  •   Péter Török    16 年前

    简短的回答是:不,没有一种标准的方法可以做到这一点。

    必须使用本机SQL。

    您可以扩展Oracle Hibernate方言并添加一些用户函数/扩展以使Hibernate生成previous或connect by子句,但这将阻止应用程序严格依赖JPA和数据库。

        2
  •  1
  •   itsadok    15 年前

    首先,假设在这个层次中,“父亲”可以有多个孩子,然后 father 字段应注释为 @ManyToOne .

    如果您有一个所有树成员共享的字段,或者如果树包含整个表,那么它 虽然不是通过单个JPA查询,但可以以有效的方式使用JPA。

    只需预取树的所有成员,然后遍历树:

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

    注意 @OrderedBy 子类别字段上的注释。

    现在,您可以通过首先将所有类别加载到一个混乱的列表中,以便它们都在内存中,然后遍历树来获取整个树。

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

    我现在只在学习JPA,所以我可能遗漏了一些关键的东西,但这种方法似乎对我有用。

    推荐文章