Problem Description
Our use case requires that we build a tree of our entity, Subject, and pass it all the way to our rich client. Subject has four collection associations which need to be fetched/initialized for the tree to be complete.
The Subject mapping follows, however, the collections which require initialization are
names (an internationalizable Map of Subject names),
children (composite Subject leaf nodes),
parentsIds (poorly named legacy association), and
attributes. We do not require descriptions in our tree.
We'd like for our DAO to fetch the whole graph prior to sending it to the assembler. Otherwise we run into the N+1 select problem because our assembler will have to navigate the graph and for each child will issue a select statement.
As we understand it this is unavoidable because you can only eager fetch one collection per HQL or Criteria query.
Question
Our question is how're others doing this for similar use cases with multiple collections that require fetching? Is walking the tree the best way?
In HiA step 2 in solving the N+1 select problem involves:
Quote:
Navigate the object graph, which will consist entirely of objects that have already been fetched from the database.
This assumes that all data is fetched in the initial query. How is this possible if eager fetching is understandably limited to one collection per query?
Currently our DAO looks something like this:
Code:
...
subject = (Subject) session.createCriteria(Subject.class)
.add( Expression.eq("id", (String) root.getId()))
.setFetchMode("children", FetchMode.EAGER)
.uniqueResult();
...
we then assemble the tree within the same session. We've read all the performance docs and the HiA chapters on optimizing object retrieval. Just want to be confident that this is the best approach. We're about to attempt batch-fetching, but consider this mapping dangerous as Subject has many other use-case clients...
More details provided upon request.
Regards,
Roll
Subject mapping:Code:
<hibernate-mapping>
<class
name="com.casebank.spotlight.domain.Subject"
table="subject"
dynamic-update="false"
dynamic-insert="false"
select-before-update="false"
>
<cache usage="read-write" />
<id
name="id"
column="id"
type="java.lang.String"
unsaved-value="0"
>
<generator class="uuid.hex">
<!--
To add non XDoclet generator parameters, create a file named
hibernate-generator-params-Subject.xml
containing the additional parameters and place it in your merge dir.
-->
</generator>
</id>
<map
name="names"
table="subject_name"
lazy="true"
sort="unsorted"
inverse="false"
cascade="all"
>
<cache
usage="nonstrict-read-write"
/>
<key
column="subject_id"
>
</key>
<index
column="locale_id"
type="string"
/>
<element
column="translation"
type="string"
not-null="false"
unique="false"
/>
</map>
<map
name="descriptions"
table="subject_description"
lazy="true"
sort="unsorted"
inverse="false"
cascade="all"
>
<cache
usage="nonstrict-read-write"
/>
<key
column="subject_id"
>
</key>
<index
column="locale_id"
type="string"
/>
<element
column="translation"
type="string"
not-null="false"
unique="false"
/>
</map>
<list
name="children"
table="subject_hierarchy"
lazy="true"
inverse="false"
cascade="none"
>
<cache
usage="nonstrict-read-write"
/>
<key
column="parent_id"
>
</key>
<index
column="sort_order"
/>
<many-to-many
class="com.casebank.spotlight.domain.Subject"
column="child_id"
outer-join="false"
/>
</list>
<bag
name="parentsIds"
table="subject_hierarchy"
lazy="true"
inverse="false"
cascade="none"
>
<cache
usage="nonstrict-read-write"
/>
<key
column="child_id"
>
</key>
<element
column="parent_id"
type="string"
not-null="false"
unique="false"
/>
</bag>
<list
name="attributes"
table="subject_attribute"
lazy="true"
inverse="false"
cascade="none"
>
<cache
usage="nonstrict-read-write"
/>
<key
column="subject_id"
>
</key>
<index
column="sort_order"
/>
<many-to-many
class="com.casebank.spotlight.domain.Attribute"
column="attribute_id"
outer-join="false"
/>
</list>
<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-Subject.xml
containing the additional properties and place it in your merge dir.
-->
</class>
</hibernate-mapping>
Hibernate Version: 2.1.6
DB: MS SQL Server 2000