Efficient representation of Hierarchies in Hibernate.

Posted by Alison G on Stack Overflow See other posts from Stack Overflow or by Alison G
Published on 2010-01-14T20:20:38Z Indexed on 2010/05/14 16:04 UTC
Read the original article Hit count: 302

Filed under:
|
|
|
|

I'm having some trouble representing an object hierarchy in Hibernate. I've searched around, and haven't managed to find any examples doing this or similar - you have my apologies if this is a common question.

I have two types which I'd like to persist using Hibernate: Groups and Items.
* Groups are identified uniquely by a combination of their name and their parent.
* The groups are arranged in a number of trees, such that every Group has zero or one parent Group.
* Each Item can be a member of zero or more Groups.

Ideally, I'd like a bi-directional relationship allowing me to get:
* all Groups that an Item is a member of
* all Items that are a member of a particular Group or its descendants.
I also need to be able to traverse the Group tree from the top in order to display it on the UI.

The basic object structure would ideally look like this:

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() { ... }  
    ...
}

Originally, I had just made a simple bi-directional many-to-many relationship between Items and Groups, such that fetching all items in a group hierarchy required recursion down the tree, and fetching groups for an Item was a simple getter, i.e.:

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;
    }
    ...
}

However, this resulted in multiple database requests to fetch the Items in a Group with many descendants, or for retrieving the entire Group tree to display in the UI. This seems very inefficient, especially with deeper, larger group trees. Is there a better or standard way of representing this relationship in Hibernate?

Am I doing anything obviously wrong or stupid?


My only other thought so far was this: Replace the group's id, parent and name fields with a unique "path" String which specifies the whole ancestry of a group, e.g.:
/rootGroup
/rootGroup/aChild
/rootGroup/aChild/aGrandChild

The join table between Groups and Items would then contain group_path and item_id.

This immediately solves the two issues I was suffering previously:
1. The entire group hierarchy can be fetched from the database in a single query and reconstructed in-memory.
2. To retrieve all Items in a group or its descendants, we can select from group_item where group_path='N' or group_path like 'N/%'

However, this seems to defeat the point of using Hibernate. All thoughts welcome!

© Stack Overflow or respective owner

Related posts about java

Related posts about hibernate