Thursday, August 25, 2005

Hibernate report query

I am still in training, but the last few days' material and lab work has been heavier than the first day's, so I didn't have any time to blog. We are deep in hibernate territory now, and I have to say, hibernate report query is pretty impressive stuff.

I've been using ORM tools for a while, first with JDO, then hibernate. Every time I try to tell some seasoned JDBC developer to use hibernate, their first question is always "does it support table joins?" I would say "yes, you can create relationships between your objects, and navigate between them." Then they'd say, "what if I want some columns from one table, some other columns from another one, etc. etc.?" I never had a good answer for that.

Until this week when I learned about hibernate report queries. This stuff is tailor made to answer the questions above. Unfortunately it's not mentioned at all in the hibernate reference manual, and I couldn't find any information on their web site. So let's look at an example here that might give you some idea about the power of report query.

Suppose we have a CD management system. A CD belongs to a Category; it has a list of Tracks; it also has an Author, which has an AuthorInfo that lists the bio, and an Address. If it's a bit confusing, don't worry as it's just an example. Now let's say we want to display some of this informaiton on a web page, but instead of everything, we just want to show the title of the cd, the name of the artist who authored it, the price of the cd, the name of the category, the bio of the artist, and which state the artist is from. Without report query, you'd have to retrieve all these objects, navigate through them to build up the result: it's hard to do it efficiently and there's a lot of code to write. Even with JDBC, the SQL gets kinda hairy too: you need to do a four way table join.

Let's see how we do this with a report query. First, we create a POJO class, CDInfo, to hold the attributes we need. On hibernate 2.x, you can do this to populate it in one shot:

select new CDInfo(cd.title, artist.name, cd.price, cat.name, info.bio, artist.address.state)
from Category cat
join cat.cds cd
join cd.author artist
join artist.authorInfo info
where cat.id = 1

Pretty neat, isn't it? In hibernate 3.x, you can even do this:

select new CDInfo(cd.title, cd.author.name, cd.price, cd.category.name, cd.author.authorInfo.bio, cd.author.address.state)
from CD cd
where cd.category.id = 1

That kinda gives you the "WOW" effect, doesn't it?

Monday, August 22, 2005

Spring/Hibernate Training 4

RTFDTD

For an open source project, spring has pretty good documentation. Their reference manual is in both HTML and PDF format, and is updated frequently for new releases. But still, sometimes the reference manual lags behind the rather active development process, and it doesn't cover every last bit of information.

For xml context files, surprisingly, everything you want to know is in the DTD. The DTD covers every imaginable element and attribute, obviously; additionally, it has tons of useful comments sprinkled liberally in the file. Spring is probably unique in this aspect: other open source projects (e.g. Hibernate) tend to have sparsely populated DTDs.

So next time if someone asks you a spring question that you are too tired to answer, instead of saying "RTFM", you can say "RTFDTD".

Spring/Hibernate Training 3

A simpler way to define properties

The spirng xml context files are, well, xml, so they can be verbose at times. One of the worst offenders is for defining properties:

<properties name="myProperties">
<props>
<prop key="myFirstKey">myFirstValue</prop>
<prop key="mySecondKey">mySecondValue</prop>
</props>
</properties>

The same properties can be expressed as this:

<properties name="myProperties">
<value>
myFirstKey=myFirstValue
mySecondKey=mySecondValue
</value>
</properties>

That's much better, isn't it?

Spring/Hibernate Training 2

Five ways to wire up collaborators

This must be in the spring manual somewhere. But, well, who reads manuals? So here are the five ways to inject dependencies (and some of my thoughts):

First, via constructors. This would make an oject purist happy, as the objects would be in a consistent state after construction. The drawback is if you have more than one constructor argument, even just two or three, your context file becomes hard to understand. For example

<bean id="foo" class="somepackage.Foo">
<constructor-arg><ref bean="bar"/></constructor-arg>
<constructor-arg><value>1</value></constructor-arg>
<constructor-arg><value>true</value></constructor-arg>
</bean>

That wasn't very clear, was it?

Which brings us to the second way to inject dependencies: via setters. People usually raise objections when they first run into this: your ojects are invalid! You have to remember to call the setters after you construct them! But in reality, you get used to them after a while. This looks so much clearer:

<bean id="foo" class="somepackage.Foo">
<property name="bar"><ref bean="bar"/></property>
<property name="intValue"><value>1</value></property>
<property name="booleanValue"><value>true</value></property>
</bean>

The last three methods are all through autowiring, eith by type, by name or by constructor arguments (which can only be by type). These are cool for fast prototypes, as everything is wired together like magic. But in a production environment, it's going to be a nightmare for others to understand and maintain your context files.

Spring/Hibernate Training 1

This week I am at a week-long on-site Spring/Hibernate training class taught by Richard Hightower. Now, I've been doing this stuff for a while, so most of the material is not new to me. But still, I am finding bits of interesting information here and there. So here is my "real time" blog on the stuff that other people might also find useful.

Id vs. name

In spring context files, bean definitions can have either an "id" or a "name" attribute. I think I've read about these before, but I couldn't remember exactly what the differences are. Turns out they server the same purpose, i.e. uniquely identifying the bean being defined. The only difference is "name" can be any string ("foo", "/bar" etc.), while "id" has to be a valid XML ID. This difference is significant when you reference a bean, with either "bean" or "local". With "bean", you can use either id or name (e.g. <ref bean="/foo">), but with "local", you can only refer to XML IDREFs, so they have to be IDs. So <ref local="/foo"> would give you an XML validation error.