http://seancorfield.github.io for newer blog posts." />

An Architect's View

CFML, Clojure, Software Design, Frameworks and more...

An Architect's View

Hibernate and Inheritance

September 7, 2008 · No Comments

I'm already used to the magic that is Transfer and I can't imagine building a ColdFusion application without it. Adobe have said they're looking at integrating Hibernate into "Centaur" and showed some simple examples of how it might work in their keynote at CFUNITED (I expect we'll see more at MAX - you are going to MAX, right?). Hibernate is the de facto standard ORM for the Java world and it is very robust, scalable and feature-rich. We've been using Hibernate for a while to manage the persistence of our business objects and that has driven us toward Groovy for those business objects since, right now, you cannot use Hibernate with ColdFusion Components in any meaningful way and we didn't want to write all the verbose code that Java would require. A recent discussion on the Transfer mailing list has focused on how to model one-to-one relationships and why Transfer doesn't support them directly. This is one area in which Hibernate's features go far beyond what Transfer offers - and part of the reason for us to "switch" to Hibernate for future product development. Another modeling quandary when it comes to persistence is how to handle inheritance.Suppose you have a number of "content" object types such as blog entries, bookmarks, files and tasks. They all extend a base content type so that common behavior can be applied polymorphically across all types of content, such as adding comments or rating an item. You have several choices on how to represent this in a database: one table for each child object (with the parent object's data represented as columns in each child object's table), one table for the base class data and one table for each child object (with a one-to-one relationship between child and parent - hence the paragraph above), a single sparse table for all data types (with a discriminator column indicating what type of data that row holds and columns being null where they do not apply), or other options involving association tables and so on. The nice thing about Hibernate is that it handles all of these options out-of-the-box. In our example, most of the metadata about content is held in the base class and the child classes only have a few additional fields. We're using Hibernate annotations so we can declare our base content class like this:
@Entity
@Table(name="content")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
   name="content_type",
   discriminatorType=DiscriminatorType.STRING
)
class Content implements Serializable {
@Entity declares that this is a persistent object (and that's why Content has to implement Serializable). We could let Hibernate choose the table name but we want to specify a lowercase name (@Table(name="content")). The other annotations define:
  • How we want Hibernate to represent the inheritance in the database - as a single sparse table
  • How we want Hibernate to distinguish between different types of object in the table - it will add a column called content_type of type varchar (or whatever your database uses for string data)
We're letting Hibernate manage our schema - while we're actively developing - so Hibernate will happily create a table called content, add a column called content_type along with all the other attributes specified in the class such as the auto-generated primary key:
@Id @GeneratedValue
Long id
Now let's look at one of the extended classes:
@Entity
@DiscriminatorValue("bookmark")
class Bookmark extends Content {

   String link

}
This declares that Bookmark is a persistent object that extends Content and will have its content_type column set to "bookmark". Hibernate will add a column, link, to the content table that will be null for other types of content. Similarly, here's how a comment on a content item is represented:
@Entity
@DiscriminatorValue("comment")
class Comment extends Content {

   // a link to the content item    // on which this comment was made    @ManyToOne
   @JoinTable(name="comment_content")
   Content   content
}
A comment is content (and can therefore be rated and commented on in turn) and, because this is represented as part of the content table, Hibernate uses an association table for the relationship and we override the default name (which would be content_content) to make it more descriptive. That association table contains two columns: id, the key of the comment, and contentId, the key of the content item on which this comment was made. That's it.

Tags: grails · j2ee · orm

0 responses so far ↓

  • There are no comments yet...Kick things off by filling out the form below.

Leave a Comment

Leave this field empty