HIBERNATE JBoss.org
 |  Register  | 
     
News 
About 
   Feature List 
   Road Map 
Documentation 
   Related Projects 
   External Documentation 
Download 
Forum & Mailinglists 
Support & Training 
JIRA Issue Tracking
Wiki Community Area


Hibernate Public Training Courses


Get Hibernate in Action eBook!


JavaWorld 2003 Finalist


Jolt Award 2004 Winner
      
Documentation > Community Area > Lightweight Class

Lightweight Class

Suppose I have the following persistent class:

public class Document implements Node {
   private Long _key;
   private String _name;
   private Calendar _created;
   private Calendar _updated;
   private Folder _folder;
   private Clob _text;
   public String getKey() { return _key; }
   public void setKey(Long key) { _key = key; }
   public String getName() { return _name; }
   public void setName(String name) { _name = name; }
   public Calendar getCreated() { return _created; }
   public void setCreated(Calendar created) { _created = created; }
   public Calendar getUpdated() { return _updated; }
   public void setUpdated(Calendar updated) { _updated = updated; }
   public Folder getFolder() { return _folder; }
   public void setFolder(Folder folder) { _folder = folder; }
   public Clob getText() { return _text; }
   public void setText(Clob text) { _text = text; }
}

All properties of this class are mapped to columns of the DOCUMENTS table. For performance I don't want to open a stream to the underlying CLOB data every single time I retrieve a list of documents, rename a document, move a document, etc. Some commercial O/R mapping tools allow an object to be initially fetched with a default set of properties initialized. The remaining properties are fetched when they are first accessed. Hibernate does not have this feature. However, there is a popular workaround that allows even better performance than that approach.

We break our Document class into a "lightweight" superclass and "heavyweight" subclass:

public class DocumentInfo implements Node {
   private Long _key;
   private String _name;
   private Calendar _created;
   private Calendar _updated;
   private Folder _folder;
   private Clob _text;
   public String getKey() { return _key; }
   public void setKey(Long key) { _key = key; }
   public String getName() { return _name; }
   public void setName(String name) { _name = name; }
   public Calendar getCreated() { return _created; }
   public void setCreated(Calendar created) { _created = created; }
   public Calendar getUpdated() { return _updated; }
   public void setUpdated(Calendar updated) { _updated = updated; }
   public Folder getFolder() { return _folder; }
   public void setFolder(Folder folder) { _folder = folder; }
}

public class Document extends DocumentInfo {
   private Clob _text;
   public Clob getText() { return _text; }
   public void setText(Clob text) { _text = text; }
}

We use the following mapping:

<class name="DocumentInfo" table="DOCUMENTS">
   <id name="key" type="long" column="ID">
       <generator class="native"/>
   </id>
   <property name="name"/>
   <property name="created"/>
   <property name="updated"/>
   <many-to-one name="folder"/>
</class>

<class name="Document" table="DOCUMENTS" polymorphism="explicit">
   <id name="key" type="long" column="ID">
       <generator class="native"/>
   </id>
   <property name="name"/>
   <property name="created"/>
   <property name="updated"/>
   <many-to-one name="folder"/>
   <property name="text"/>
</class>

Now the application may retrieve instances of DocumentInfo if it is interested in the info only, or instances of Document if it needs access to the text property. Because we have mapped Document with polymorphism="explicit", any queries like:

from DocumentInfo
from Node
from java.lang.Object

return instances of DocumentInfo. The following query returns only instances of Document:

from d in class Document

Caveat: you cannot load the same database row as two different objects. As such, you cannot first load the DocumentInfo followed by the Document for the same Document ID as Hibernate will not upcast the object. For example, doing the following will cause a ClassCastException:

DocumentInfo info = (DocumentInfo) session.load(DocumentInfo.class, new Long(1));
Document doc = (Document) session.load(Document.class, new Long(1));

If you want to get the same Document row as a DocumentInfo and a Document, you will need to use session.evict() on DocumentInfo first.

Note that arguably Hibernate does not really need lazy property fetching, since the query language supports projection, allowing the Java code to fetch exactly the needed properties.

      

coWiki