Hibernate中层次结构的有效表示

Arm*_*and 5 java tree orm hibernate graph

我在Hibernate中表示对象层次结构时遇到了一些麻烦.我一直在搜索,并没有设法找到这样或类似的任何例子 - 如果这是一个常见问题,你有道歉.

我有两种类型,我想继续使用Hibernate:Groups和Items.
*通过名称和父母的组合唯一地识别组.
*这些组被安排在许多树中,这样每个组都有零个或一个父组.
*每个项目可以是零个或多个组的成员.

理想情况下,我想要一个双向关系,允许我得到:
*所有组,其中一个项目是
*所有项目的成员,所有项目是特定组或其后代的成员.
我还需要能够从顶部遍历组树,以便在UI上显示它.

理想情况下,基本对象结构如下所示:

class Group {
    ...
    /** @return all items in this group and its descendants */
    Set<Item> getAllItems() { ... }

    /** @return all direct children of this group */
    Set<Group> getChildren() { ... }
    ...
}

class Item {
    ...
    /** @return all groups that this Item is a direct member of */
    Set<Group> getGroups() { ... }  
    ...
}
Run Code Online (Sandbox Code Playgroud)

最初,我刚刚在Items和Groups之间建立了一个简单的双向多对多关系,这样获取组层次结构中的所有项目都需要在树中递归,并且为Item获取组是一个简单的getter,即:

class Group {
    ...
    private Set<Item> items;
    private Set<Group> children;
    ...
    /** @return all items in this group and its descendants */
    Set<Item> getAllItems() {
        Set<Item> allItems = new HashSet<Item>();
        allItems.addAll(this.items);
        for(Group child : this.getChildren()) {
            allItems.addAll(child.getAllItems());
        }
        return allItems;
    }

    /** @return all direct children of this group */
    Set<Group> getChildren() {
        return this.children;
    }
    ...
}

class Item {
    ...
    private Set<Group> groups;
    /** @return all groups that this Item is a direct member of */
    Set<Group> getGroups() {
        return this.groups;
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

但是,这导致多个数据库请求获取具有许多后代的组中的项目,或者用于检索要在UI中显示的整个组树.这似乎非常低效,特别是对于更深,更大的组树.在Hibernate中有没有更好或更标准的方式来表示这种关系?

我做了什么明显错误或愚蠢的事情吗?


到目前为止,我唯一的另一个想法是:用一个唯一的"path"字符串替换组的id,parent和name字段,该字符串指定组的整个祖先,例如:
/ rootGroup
/ rootGroup/aChild
/ rootGroup/aChild/aGrandChild

然后,Groups和Items之间的连接表将包含group_path和item_id.

这立即解决了我之前遇到的两个问题:
1.整个组层次结构可以在单个查询中从数据库中获取并在内存中重建.
2.要检索组或其后代中的所有项目,我们可以从group_item中选择group_path ='N'或group_path类似'N /%'

但是,这似乎打败了使用Hibernate的重点.欢迎所有的想法!

Jim*_*ows 4

我认为真正的问题是你希望性能在哪里受到影响。如果你宣称你所有的关系都是懒惰的,并拉出你需要的东西,那么你就会随着时间的推移而传播打击。在许多情况下,这意味着您的用户(人或芯片)感知到更快的反应时间。即使您一次处理整个图,您实际上也不需要同时将整个图存储在内存中。

另一方面,拉动整个图表可以将性能放在首位,同时使操作速度更快。

两者之间最大的区别是您的具体用例。如果这是一个网络服务器,将整个图拉入内存将会杀死服务器。无论如何,大多数人都无法处理超过 7-10 个选项,而且整个图表很容易让用户不知所措,导致 UI 难以导航。

还要记住这些优化规则:

  1. 说真的,不要。在性能问题上投入硬件比优化代码到不再可维护的程度要便宜。
  2. 如果您认为必须这样做,请使用分析工具找到第一个瓶颈并修复它。