Hibernate: How to model a double parent/child relationship
I got a pretty simple parent/child relationship here, which looks like this:
Email servers have n folders. Folders can have n (sub-)folders. Folders have a reference to their parent folder as well as to the email server they belong to.
My mapping files look like this:
MailServer.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 02.05.2011 12:32:52 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="test.MailServer" table="MAILSERVER">
<id name="id" type="long" access="field">
<column name="MAIL_SERVER_ID" />
<generator class="native" />
</id>
<bag name="folders" table="FOLDERS" lazy="false" i开发者_如何学编程nverse="true" cascade="all-delete-orphan">
<key column="MAIL_SERVER_ID"></key>
<one-to-many class="test.Folder" />
</bag>
</class>
</hibernate-mapping>
Folder.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 04.05.2011 15:02:31 by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="test.Folder" table="FOLDERS">
<id name="id" type="long" access="field">
<column name="FOLDER_ID" />
<generator class="native" />
</id>
<many-to-one name="mailServer" column="MAIL_SERVER_ID" not-null="true" />
<bag name="folders" table="FOLDERS" lazy="false" inverse="true" cascade="all">
<key column="PARENT_FOLDER_ID" not-null="false"></key>
<one-to-many class="test.Folder" />
</bag>
<many-to-one name="parentFolder" column="PARENT_FOLDER_ID" />
</class>
</hibernate-mapping>
The problem I got, is the following.
Let's say, I have the following hierachy:
- MyMailServer
Folder1
- Folder2
Subfolder
Folder3
When I call hibernateSession.save(mailServerInstance);
or hibernateSession.update(mailServerInstance);
, Hibernate correctly stores everything to the database. The parent column id's are filled correctly. Same for all other references.
BUT when I load the data, Hibernate reloads the folder hierachy like this:
- MyMailServer
Folder1
Folder2
Subfolder
Folder3
I understand the reason: Subfolder has a reference to its MailServer and thus, Hibernate ads it there instead of the folder where it belongs to.
But, how do I solve this problem?
Thanks in advance!
As you already understood what Hibernate does here is logical since you're fetching all folders for given mailServer. I don't think there is a way to achieve what you want in 1 single query (not a hibernate restriction, also with plain old SQL this is not possible). I have a very similar case where I do the following:
- get root folders for mail server (-> where parent folder is null)
- for each folder get the child folders
Another solution is using Transfer Objects and you map the entities to the transfer objects so that the required structure is obtained.
It all depends on your use case which (if any) solution is appropriate. E.g. if you can execute an AJAX call each time a folder is expanded (tree structure) then the first solution is ideal.
I worked around this by replacing
<bag name="folders" table="FOLDERS" lazy="false" inverse="true" cascade="all-delete-orphan">
<key column="MAIL_SERVER_ID"></key>
<one-to-many class="test.Folder" />
</bag>
in MailServer.hbm.xml with
<one-to-one name="rootFolder" class="test.Folder" cascade="all" />
That did the trick.
精彩评论