OpenJPA 1.2.x使用JPQL选择树结构

时间:2010-11-05 22:42:05

标签: jpa tree jpql

我正在使用OpenJPA 1.2.x(JPA1)。问题是我无法继续使用JPQL查询树结构。

请看,我的实体:

@NamedQueries(
         { 
           @NamedQuery(
             name="Department.getFullTree",
             query="SELECT dep FROM Department dep LEFT JOIN fetch dep.children"
           )
         }
        )
@Entity
public class Department {

    public static final Long ROOT_ID = 0L;

    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="DEPARTMENT_SEQ")
    @SequenceGenerator(name="DEPARTMENT_SEQ", sequenceName="DEPARTMENT_SEQ", allocationSize=1)
    @Column(name="ID")
    private Long id;

    @Column(name="PARENT_ID")
    private Long parentId;

    @ManyToOne(targetEntity = Department.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "PARENT_ID")
    private Department parent;

    @Column(name="LABEL")
    private String label;

    @OneToMany(mappedBy = "parent", 
               targetEntity = Department.class, 
               fetch=FetchType.LAZY, 
               cascade = {CascadeType.PERSIST, CascadeType.ALL})
    private List<Department> children;

我的无状态bean方法:

public Department getFullTree(){
    em.createNamedQuery("Department.getFullTree").getResultList();
    Department root = em.find(Department.class, Department.ROOT_ID); 
    return root;
}

我的目标是从根开始获取完整的部门树。 我尝试过这种方法:

这是真的吗?我正在使用DB2。并将在未来使用它。 JPA query for getting the whole tree

这似乎不起作用: http://www.tikalk.com/java/load-a-tree-with-jpa-and-hibernate

我试过重复,但是在遍历树时遇到堆栈溢出错误(根本没有超过200个节点)。 调试输出显示root本身就是一个孩子,所以它是圆形链接结构...

我接下来要尝试什么?

UPD: 这是我的遍历代码:

public class TreeTagHelper {

    private static final Logger LOG = LoggerFactory.getLogger(TreeTagHelper.class);

    private Department root;
    private JspWriter out;

    public TreeTagHelper(Department root, JspWriter out){
        LOG.trace("#init");
        this.root = root;
        this.out = out;
    }

    public void printTree() throws Exception{
        LOG.trace("#printTree -> start");
        out.println("<ul id=\"tree-root\"> ");      
        for(Department dep : root.getChildren()){
            printNode(dep, out);
        }       
        closeUL(out);
        LOG.trace("#printTree -> end");
    }

    public static void printNode(Department dep, JspWriter out) throws Exception{
        LOG.trace("#printNode title[{}] children.size()[{}]",dep.getLabel(), (dep.getChildren() == null ? "NULL" : dep.getChildren().size()) );
        openLI(out);
        out.print("<span id=\"tree_node_"+dep.getId()+"\" class=\"ekp-tree-node\" onclick=\"ekpCommon.tree.toggleBullet(this)\">"+dep.getLabel()+"</span>");
        if(dep.getChildren()!=null){
            openUL(out);
            for(Department child : dep.getChildren()){
                printNode(child, out);
            }
            closeUL(out);
        }

        closeLI(out);
    }

    public static void openUL(JspWriter  out) throws Exception{
        out.println("<ul>");
    }

    public static void closeUL(JspWriter out) throws Exception{
        out.println("</ul>");       
    }

    public static void openLI(JspWriter out) throws Exception{
        out.println("<li>");
    }

    public static void closeLI(JspWriter out) throws Exception{
        out.println("</li>");       
    }

LOG.trace(“#printNode title [{}] children.size()[{}]”,dep.getLabel(),(dep.getChildren()== null?“NULL”:dep.getChildren( ).size()));

总是输出:“#printNode title [所有部门] children.size()[19]” 似乎根(“所有部门”)有19个孩子。这是真的,我在我的数据库中检查过它。 但每个孩子都是根! 所以这是无限的结构...... ??? Root没有孩子?它取而代之?

3 个答案:

答案 0 :(得分:1)

  

我试过重复,但是在遍历树时遇到堆栈溢出错误(根本没有超过200个节点)。调试输出显示root本身就是一个孩子,所以它是圆形链接结构...

那么您的数据很可能是错误的。仔细检查根没有父。

答案 1 :(得分:0)

我认为你所做的是正确的,应该有效。您正在将完整的树结构加载到持久性上下文中,然后获取对根节点的引用。也许你的树遍历有问题?这将是唯一可能导致StackOverflowError的事情。你能发贴你的代码吗?

答案 2 :(得分:0)

请参阅我的数据库结构:

ID    PARENT_ID    LABEL
0     0        All Departments
1000   0           Central office

这就是为什么JPA不起作用的原因:(

见第一行。它是树的根。看起来像JPA将它读作一个引用自身的子进程(PARENT_ID确实存在于表中,因此可以执行JOIN)。

我更改了数据库值:

ID    PARENT_ID    LABEL
0     -1           All Departments
1000   0           Central office

现在它有效!是啊! :)