tags:

views:

32

answers:

1

Many times we need only one readonly field from a joined table. e.g, in following case I need only (customer)name from Customers table.For this I am creating entire Customer object, that is consisting of tens of other properties that I don't need in Orders.
This issue becomes more significant if such field is being fetched for child class e.g., (product)name for item object. This is leading to creation of hundreds or even thousands of "product" objects for one order just to provide product name.
One way to deal with such situation could be to make a additional CustomerName class with only one property. This approach does'nt look elegant because it could end up creating many similar classes for same table. Can someone suggest me a better solution?

Example Mapping with usual Customer and Product classes:

  <class name="Order" table="Orders">
    <id column="ID" name="id" type="long">
      <generator class="native" />
    </id>
    <property name="customerId" type="int" />
    <many-to-one class="Customer" name="customer" column="customerId" insert="false" update="false" fetch="join" />

    <class name="OrderItem" table="OrderItems">
      <id column="id" name="itemId" type="long">
        <generator class="native" />
      </id>
      <property name="productId" type="long" />

      <many-to-one name="order" column="orderId" not-null="true" />
      <many-to-one class="Product" name="product" column="productId" insert="false" update="false" fetch="join" />

    </class>
  </class>

Example with additional CustomerName and ProductName classes:

<class name="Order" table="Orders">
    ...
    <many-to-one class="CustomerName" name="customer" column="customerId" insert="false" update="false" fetch="join" />
    <class name="OrderItem" table="OrderItems">
      .....
      <many-to-one class="ProductName" name="product" column="productId" insert="false" update="false" fetch="join" />
    </class>
  </class> 
A: 

If you want to avoid reading too much columns, you don't really have many solutions:

  1. use SQL projections (and maybe a select new for typesafe results),
  2. use a lighter object as you mentioned,
  3. use lazy property fetching.

Regarding the latest option, I suggest reading (carefully) the relevant section of the documentation:

19.1.7. Using lazy property fetching

Hibernate3 supports the lazy fetching of individual properties. This optimization technique is also known as fetch groups. Please note that this is mostly a marketing feature; optimizing row reads is much more important than optimization of column reads. However, only loading some properties of a class could be useful in extreme cases. For example, when legacy tables have hundreds of columns and the data model cannot be improved.

To enable lazy property loading, set the lazy attribute on your particular property mappings:

<class name="Document">
       <id name="id">
        <generator class="native"/>
    </id>
    <property name="name" not-null="true" length="50"/>
    <property name="summary" not-null="true" length="200" lazy="true"/>
    <property name="text" not-null="true" length="2000" lazy="true"/>
</class>

Lazy property loading requires buildtime bytecode instrumentation. If your persistent classes are not enhanced, Hibernate will ignore lazy property settings and return to immediate fetching.

For bytecode instrumentation, use the following Ant task:

<target name="instrument" depends="compile">
    <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
        <classpath path="${jar.path}"/>
        <classpath path="${classes.dir}"/>
        <classpath refid="lib.class.path"/>
    </taskdef>

    <instrument verbose="true">
        <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
            <include name="*.class"/>
        </fileset>
    </instrument>
</target>

A different way of avoiding unnecessary column reads, at least for read-only transactions, is to use the projection features of HQL or Criteria queries. This avoids the need for buildtime bytecode processing and is certainly a preferred solution.

You can force the usual eager fetching of properties using fetch all properties in HQL.

Personally, I would favor option #1 first. If not possible, I would go for option #2 (yes it introduces more maintenance but you can keep this under control if you only use this solution for parts that are really a problem). I'm not fan of option #3.

Pascal Thivent
option #1 looks appealing to me too. I am going to try it first and see what happens
Leslie Norman