获取整个树的JPA查询

时间:2010-04-08 08:51:46

标签: java hibernate jpa persistence

我有一个模拟所有类别的类,它们可以按层次排序。

@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 个答案:

答案 0 :(得分:8)

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

您必须使用本机sql。

您可以扩展Oracle Hibernate Dialect并添加一些用户函数/扩展来让hibernate生成PRIOR或CONNECT BY子句,但这会阻止您的应用程序严格禁止JPA和数据库。

答案 1 :(得分:1)

首先,假设在这个层次结构中“父亲”可以有多个孩子,那么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;
}

注意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,所以我可能会遗漏一些至关重要的东西,但这种方法似乎对我有用。