Pencils Down

This weblog is about my experiences in software development

Browsing Posts published in February, 2009

After much searching around the Internet I have come to the conclusion that Hibernate really doesn’t support self-referencing tables. The typical example is something like this table:

Table Category
---------------
categoryId int
name varchar(50)
parent int

In this example the Hibernate code would be something like:

Category parent = ...
Category child = ...
child.setParent(parent)
dao.create(child);
//this does not appear to actually do anything in a self-referencing table
parent.getChildren().add(child);
dao.saveOrUpdate(parent);
session.flush();

//and then later on

Category category = categoryDao.something();
for(Category child:category.getChildren()) {
  //do something with each child
}

Notes:

  • Since the reference is in the same table, the above add() to the parent children does nothing.
  • The setParent() call is just setting the parent column directly in the Category object – no database action is taking place.
  • Calls to getChildren() are doing a simple query unlike other getObject ORM calls in Hibernate
  • Calls to getParent() are also doing abnormal ORM calls

All of the above code ‘works’. It just doesn’t work like anything else really in Hibernate.

In our application we have the typical hierarchical object organization that is reflected in the data store.  This fits nicely into a relational database.  Being a modern shop (surprising given the industry – defense) we use Hibernate for the ORM.  Unfortunately most developers, while somewhat familiar with Hibernate and SQL, have very little experience using HQL.

A typical problem would be list all the level 3 objects in the system.  So, you might find code like:

Set<Level3Id,Level3> hash = new HashSet<Level3Id,Level3>(); 
Set<TopLevel> topLevels = dao.findAll();
for(TopLevel top:topLevels) {
    Set<Level2> level2s = top.getLevel2s();
    for(Level2 level2:level2s) {
        Set<Level3> level3s = level2.getLevel3s();
        for(Level3 level3:level3s) {
            hash.put(level3.id, level3);
        }
    }
}

where the developer is constructing a HashSet to produce a unique list of level 3 objects.  This is a simple example, there are many use cases where we traverse much lower into the object graph using some complicated tests (WHERE clauses).

The alternative HQL is trivial in comparison and the performance improvement is astounding (remember due to lazy loading each of the objects above would have to be materialized even though we never really wanted them in the first place):


List<Level3> level3s = session
        .createQuery("select distinct level3 from Level3 as level3")
        .list();

I guess the message is to try and think about the underlying SQL database that you have available.  While Hibernate obscures access to the underlying database it normally exposes all of the functionality present in the SQL into HQL in some manner.  So, if you could do something neat in SQL chances are you can do the same neat access in HQL.

IceFaces Rocks!

No comments

IceFaces is a Java AJAX framework (http://icefaces.org).  Open-source.  Through it’s live connectivity to the DOM on the client ALL interactions are performed in sequence to a back-end supporting beans.

IceFaces has all the built-ins you would expect to be able to build a RIA app.  The best part is it works and even better: the tutorials on the site work!  There are so many open source frameworks out there with very little documentation.  More typically the x.org site supporting your open source framework has limited, theoretical documentation – think of Hibernate or Spring – both excellent frameworks, but very sparse documentation on how to do regular, everyday things.  So, you end up poking around on the network and typically find several leads that are just wrong.

Such a pleasure to use a tool that you don’t have to waste time on redeveloping the wheel every day.

Expecting to see something about snow, Yahoo Weather reported “Unknown Precipitation” for my area. 

 unknown1.JPG