使用hibernate控制叶子加载父/子层次结构

时间:2011-09-07 13:20:35

标签: java hibernate collections

我正在尝试从数据库加载父/子对象的图形(类似于Java的DefaultMutableTreeNode对象)。 2之间有一个简单的一对多关联。图的级别总数是已知的,因此我确切地知道调用'getChildren()'方法的次数。 我想要做的是不要为实际的叶节点调用此方法。通常,该图由一些非叶节点和几百个叶节点组成。如果我在hb映射中指定lazy=false,我会从hb为叶子节点的子节点获得数百个不必要的查询,而我事先知道它们不需要它们(因为我知道树上的级别总数) 。 不幸的是我不能使用lazy=true并且只循环到叶节点的父节点,因为我正在处理断开连接的客户端/服务器模型并使用beanlib来加载整个对象图(包含其他几个对象)。

所以我试图找到一种方法来拦截'children'集合的加载,并指示hb在到达叶节点时停止。有没有办法做到这一点? 我正在寻找两种解决方案: 我想到的是:当我调用node.getChildren()方法(在一个hb会话中)时,通常hb会执行一个db查询来获取子进程:有没有办法拦截这个调用而只是没有它?我知道没有孩子所以我只是想让它快速失败(实际上我根本不想做它)。

谢谢 科斯塔斯

3 个答案:

答案 0 :(得分:1)

为什么不使用布尔leaf属性,如果getChildren为真,则让leaf方法返回空列表?

private boolean leaf;

private List<Node> children;

public List<Node> getChildren() {
    if (leaf) {
        return Collection.<Node>emptyList();
    }
    return children;
}

答案 1 :(得分:0)

除非您的数据库与发出这些查询的java代码共存,否则每个节点发出一个查询可能是一个性能瓶颈,即使它只是每个内部节点的查询。既然您知道了树的最大级别(为了示例,我们假设为3),以下内容应该在一个查询中获取整个树:

from Node n1
left join n1.children as n2
left join n2.children as n3
left join n3.children as n4

该方法的缺点是结果集将为每个后代的每个内部节点重复数据,即带宽乘以树级数。如果这是一个问题因为您有多个级别,您可以为该集合启用批量提取,甚至可以手动执行类似操作:

List<Node> border = Collections.singletonList(rootNode);
while (!border.isEmpty()) {
    List<Integer> ids = new ArrayList<Integer>();
    for (Node n : border) {
        ids.add(n.getId());
    }

    // initialize the children collection in all nodes in border
    session.createQuery("from Node n left join n.children where n.id in ?").setParameter(0, ids).list();

    List<Node> newBorder = new ArrayList<Node>();
    for (Node n : border) {
        newBorder.addAll(n.getChildren());
    }
    border = newBorder;
}

这将发出与树中的级别一样多的查询,并为每个节点传输两次数据。 (有些数据库限制了一个子句的大小。你必须在该级别内批量处理,然后)

答案 2 :(得分:0)

你可以在getChildren调用周围使用AOP做类似的事情(请注意这是非常粗糙的伪代码,你必须填写“空白”):

childrenResult = node.getChildren()
if (Hibernate.isInitialized(childrenResult)) {
    return node.getChildren()
} else {
  // Do something else here
}

这样做的是当您调用getChildren并且未初始化集合时,可以对其进行加入或不允许继续处理。但是,如果项目已初始化,则允许呼叫继续。有关Hibernate.isInitialized的一点需要注意的是,它将在所有对象上返回true,但是尚未填充的延迟加载的集合。

如果您无法使用AOP,您可以随时在您的代码中自行调用getChildren。

相关问题