Some time ago, I posted a question about Composite-IDs in Hibernate. Not surprisingly, I didn’t get much for a response. Usually, each table in the database has a primary key, some unique identifier that only belongs to a single row of data, or once mapped, a single instance of an object. I was having a major headache trying to get the generated code from Hibernate-Tools to work right, and I decided (ignorantly) to eliminate the generated composite-ids and just take a column from the table and pretend it’s an id. I thought everything was ok, until I started writing hql queries that would return 1 row of data, and the same query would return 30 rows if I ran it directly against the DB.
The reason for this is that Hibernate NEEDS to have a Unique ID for each mapping in order to identify created instances of objects. If you don’t have an id column (auto-incrementing integer, uid, etc) for your table, Hibernate allows you to create a “virtual id” of sorts by using the composite-id. The idea is that you take multiple columns from your table and those columns taken together (as a composite) are used to identify a row of data.
Consider the following:
Table Person
Columns
FirstName LastName City Country BirthDate BirthTime HairColor EyeColor
There is no primary key for this table or any column that we can consider to be unique. However, we can combine fields together, which gives us our composite-id. I would say that FirstName, LastName, BirthDate, and BirthTime are probably enough to identify a row of data uniquely. What I mean by that is this:
If there is a row where this exists
FirstName = ‘Scott’ AND LastName=’Wellington’ AND BirthDate=’01/02/1970′ AND BirthTime=’05:38:00′
There are no other rows that will be returned using that criteria.
I can combine these columns together (as properties) in a simple bean that will be the ID for the mapped object that we’re working with.
If you wanted to be completely safe, you could combine all the columns together. In fact, that may be preferred, because you can then access all the properties in the same way, which we’ll see later. However, I don’t know if there’s any performance hit for doing that.
Using only FirstName and LastName for a composite-id would not be a good idea. There are too many people with the same first and last name throughout the world. Therefore, the composite-id would not be unique and could not be used.
So, let’s see how we implement this. Here is the breakdown of what we will have in this example.
class Person (corresponds to table ‘Person’ in the database)
class PersonCompositeID
hbm.xml file only for class Person
Class Person will have the following attributes:
PersonCompositeID id
String city
String country
String hairColor
String eyeColor
Class PersonCompositeID will have the attributes defined between the composite-id element tags:
String firstName
String lastName
Date birthDate
String birthTime
You also need to implement java.io.Serializable on the ID class and override the equals method and the hashCode method, which probably won’t be much fun. So you’ll want to take a good look at using a code generation tool, such as the one in Hibernate-Tools for eclipse.
Finally, it’s time to use it. So fire it up and make a simple query to retrieve a Person, preferably by just using values from a row in the DB that you already know. Once you have a hold of an instance of Person, you have to access the attributes from the appropriate class. This is what got me confused before. But it’s really quite simple, which is probably why my brain made it so difficult.
If you want to access any property that is part of the composite-id, you need to access it through the PersonCompositeID class, which is referenced in the Person class as the “id” property. So, if you want to get the lastName, you do this:
//Get or create an instance of a Person Person person = getSomePerson(); //Access the composite-id property through the id property in class Person String lastName = person.getId().getLastName();
To access a property that is not part of the composite-id, you simply do what you normally would.
Person person = getSomePerson(); String eyeColor = person.getEyeColor();
So, that should be about it. Please feel free to share your thoughts, feelings, concerns, tips, tricks, and whatever else you care to divulge. But NO QUESTIONS!
OK fine, maybe one per…ah I can’t track it anyway.
See the official documentation on this subject here: http://www.hibernate.org/hib_docs/v3/reference/en/html/mapping.html#mapping-declaration-compositeid
4 Comments
How can i add a new Data
Hey,
If i wanted to search for all people with a specific lastname using the criteria() mechanism, the code might look something like..
Criteria criteria = session.createCriteria(PersonComposite.class|PersonCompositeID.class);
criteria.add(Restrictions.eq(“lastname”,”xyz”));
But there seems to be two issues, the first since the PersonComposite class does not define a property mapping for the ‘lastname’ attribute, but the PersonCompositeID isn’t defined as a stand-alone hbm.xml file so references to lastname attribute also fail. I have a feeling the answer will be very simple!!
Hi,
You said “No Questions”, but I want to ask one question here.
If you want to update the BirthDate or any other primary key value. How will you do that ?
Because the query for update is not going to update the primary key values.
Thanks.
PPR
Please give simple example of implementation of composite key.
One Trackback/Pingback
[...] Note – If you’re looking for Hibernate Composite-Id example using xml configuration, read our earlier post here. [...]
Post a Comment