Monday, December 31, 2007

Hibernate: how to map a collection of embedded components keyed by one of the component's properties?

Quite often, during application development, I encounter the issue of mapping a collection of embedded components using Hibernate.

An embedded component is, in Hibernate, a user-defined value-typed class. It has no individual identity, hence the persistent component class requires no identifier property or identifier mapping; its lifespan is bounded by the lifespan of the owning entity instance.

When mapping a collection of embedded components, it is very important to override the equals() and hashCode() methods and compare all properties, because they are used by Hibernate to detect modifications to these components.

Very often, this collection of components also has a unique key property, that is, the collection should normally be implemented as a map indexed by the value of the key property.

The book "Java Persistence with Hibernate" and Hibernate's documentation illustrate 3 ways to map a collection of embedded components.

The first and highly recommended (by Hibernate) option is to map the collection to a set. This method requires all database columns mapped to the component class must be declared with not-null="true". It does not address the key property issue, either. I myself often find it unwieldy when dealing with the key property because it becomes my responsibility to enforce the map semantics. For example, when adding a new element, I need to iterate the set and find the existing element having the same key property value with the new element. If the existing element is found, depending on the business rule, I may throw an exception, or remove the existing element from the set and add the new element in. When you have several entity classes that have component map, you have to duplicate the same set iteration logic in many places...

The second option is to map the collection to an idbag. Again, it is the responsibility of my application to ensure the map semantics.

The third option is to map it to a map. Unfortunately, this option requires the removal of the key property from the component class. The following is the example extracted from the above-mentioned book to demonstrate the mapping of the images belonging to an item in the Caveate Emptor sample application, where the image name must be unique.

<map name="images"
table="ITEM_IMAGE"
order-by="IMAGENAME asc">

<key column="ITEM_ID"/>
<map-key type="string" column="IMAGENAME"/>
<composite-element class="Image">
<property name="filename" column="FILENAME" not-null="true"/>
<property name="sizeX" column="SIZEX"/>
<property name="sizeY" column="SIZEY"/>
</composite-element>
</map>

As can be seen from the mapping file snippet above, the "Image" component class no longer has a "name" property. This removal can be quite problematic. The key property is usually the most important property of a component class; removing this property from the component class and handle it merely as a map key not only potentially violates object oriented technology principles theoretically, but also can have significant consequences in practice. For example, the public interface of the entity class may need to be overhauled. Instead of an addImage(Image image) method, you need to provide an addImage(String imageName, Image image) method. Or, you have to create another value-type class just in order to wrap the name-deprived Image and the image name together.

Luckily, Hibernate 3.x provides a very powerful new feature called formula. This can easily solve our dilemma. It can map the component map to a map, but it does not require the removal of the key property from the component class. With formula, the above mapping can be modified to:

<map name="images"
table="ITEM_IMAGE"
order-by="IMAGENAME asc">

<key column="ITEM_ID"/>
<map-key type="string" column="IMAGENAME"/>
<composite-element class="Image">
<property name="name" type="string" formula="IMAGENAME"/>
<property name="filename" column="FILENAME" not-null="true"/>
<property name="sizeX" column="SIZEX"/>
<property name="sizeY" column="SIZEY"/>
</composite-element>
</map>

In short, it allows the "IMAGENAME" column to be mapped to both the map key and the key property of the "Image" class when loading from database. When persisting, only the map key is used to update the "IMAGENAME" column.

Now we can map a map of embedded components to a map without sacrificing the key property or writing messy codes to enforce map semantics...

5 comments:

  1. Thnx for this article. I have only one simple question...

    Is it necessary for the component's property that's keying the map to be primary key for the component ?

    I have a table for documents and a table for versions. Each one has his own SID field that is PK. I want an attribute in my Document class this way:

    Map<Integer,DocVersion> versions;

    Where the integer key is the version number, a property in the DocVersions class (but no its key!).

    Any idea?

    Thnx again...

    ReplyDelete
  2. Thanks for your comment.
    Embedded components do not have a primary key. They are just value objects.

    The unique key property mentioned in the post is just a property of the embedded components that is used as the key in the map.

    If your DocVersion is an entity instead of an embedded component, then you must use a Set instead of a Map.

    If your DocVersion is a value type, then the solution in this post can be applied.

    Hope this helps. :-)

    ReplyDelete
  3. Hey Alex,

    If you're still out there reading this. Thanks a lot for your post. After half a day of struggling myself, your post solved my problem. I wonder, why this kind of examples is not part of the hibernate documentation... I guess to make us buy the book, eh?

    Again thank you very much, Nils
    ==
    http://www.winfonet.eu

    ReplyDelete
  4. Thanks Alex.
    I was just looking for mapping embedded component.
    Your article saved my day.

    ReplyDelete
  5. INTERNATIONAL CONCEPT OF WORK FROM HOME
    Work from home theory is fast gaining popularity because of the freedom and flexibility that comes with it. Since one is not bound by fixed working hours, they can schedule their work at the time when they feel most productive and convenient to them. Women & Men benefit a lot from this concept of work since they can balance their home and work perfectly. People mostly find that in this situation, their productivity is higher and stress levels lower. Those who like isolation and a tranquil work environment also tend to prefer this way of working. Today, with the kind of communication networks available, millions of people worldwide are considering this option.

    Women & Men who want to be independent but cannot afford to leave their responsibilities at home aside will benefit a lot from this concept of work. It makes it easier to maintain a healthy balance between home and work. The family doesn't get neglected and you can get your work done too. You can thus effectively juggle home responsibilities with your career. Working from home is definitely a viable option but it also needs a lot of hard work and discipline. You have to make a time schedule for yourself and stick to it. There will be a time frame of course for any job you take up and you have to fulfill that project within that time frame.

    There are many things that can be done working from home. A few of them is listed below that will give you a general idea about the benefits of this concept.

    Baby-sitting
    This is the most common and highly preferred job that Women & Men like doing. Since in today's competitive world both the parents have to work they need a secure place to leave behind their children who will take care of them and parents can also relax without being worried all the time. In this job you don't require any degree or qualifications. You only have to know how to take care of children. Parents are happy to pay handsome salary and you can also earn a lot without putting too much of an effort.

    Nursery
    For those who have a garden or an open space at your disposal and are also interested in gardening can go for this method of earning money. If given proper time and efforts nursery business can flourish very well and you will earn handsomely. But just as all jobs establishing it will be a bit difficult but the end results are outstanding.

    Freelance
    Freelance can be in different wings. Either you can be a freelance reporter or a freelance photographer. You can also do designing or be in the advertising field doing project on your own. Being independent and working independently will depend on your field of work and the availability of its worth in the market. If you like doing jewellery designing you can do that at home totally independently. You can also work on freelancing as a marketing executive working from home. Wanna know more, email us on workfromhome.otr@gmail.com and we will send you information on how you can actually work as a marketing freelancer.


    Internet related work
    This is a very vast field and here sky is the limit. All you need is a computer and Internet facility. Whatever field you are into work at home is perfect match in the software field. You can match your time according to your convenience and complete whatever projects you get. To learn more about how to work from home, contact us today on workfromhome.otr@gmail.comand our team will get you started on some excellent work from home projects.

    Diet food
    Since now a days Women & Men are more conscious of the food that they eat hence they prefer to have homemade low cal food and if you can start supplying low cal food to various offices then it will be a very good source of income and not too much of efforts. You can hire a few ladies who will help you out and this can be a good business.

    Thus think over this concept and go ahead.

    ReplyDelete