java 获取整棵树的 JPA 查询
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2598588/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JPA query for getting the whole tree
提问by Javi
I have a class which models all categories and they can be ordered hierarchically.
我有一个对所有类别进行建模的类,它们可以按层次排序。
@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;
}
I need to get all categories ordered hierarchically (I mean every father followed by its children and fathers ordered alphabetically on each level) as they could be made for example with PRIOR in oracle. Is it possible to do this with a JPA Query (not a SQL one)?
我需要按层次排序所有类别(我的意思是每个父亲后面跟着它的孩子,父亲在每个级别上按字母顺序排列),因为它们可以用例如 oracle 中的 PRIOR 来制作。是否可以使用 JPA 查询(不是 SQL 查询)来做到这一点?
Thanks.
谢谢。
回答by Gareth Davis
The short answer is; no there isn't a standard way to do this.
简短的回答是;不,没有标准的方法可以做到这一点。
You have to use native sql.
您必须使用本机 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.
您可以扩展 Oracle Hibernate Dialect 并添加一些用户函数/扩展来让休眠生成 PRIOR 或 CONNECT BY 子句,但这会阻止您的应用程序严格独立于 JPA 和数据库。
回答by itsadok
First of all, assuming in this hierarchy a "father" can have more than one child, then the fatherfield should be annotated as @ManyToOne.
首先,假设在这个层次结构中一个“父亲”可以有多个孩子,那么该father字段应该被注释为@ManyToOne.
If you have a field that all the members of a tree share, or if the tree contains the entire table, then it ispossible to do it with JPA in an efficient way, though not through a single JPA query.
如果你有一个字段,树份额的所有成员,或者如果树包含整个表,那么它是可以使用JPA做一种有效的方式,但不是通过一个单一的JPA查询。
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 @OrderedByannotation on the subCategories field.
请注意@OrderedBysubCategories 字段上的注释。
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.
我现在只是自己学习 JPA,所以我可能会遗漏一些重要的东西,但这种方法似乎对我有用。

