“Not Possible” I was told, due to limitations of XDoclet. It is possible, but only really worthwhile under certain circumstances. Start with the understanding that if you’re going to use a composite key, you need to wrap it in a composite identifier class that is serializable and overrides hashcode() and equals().
Most people would tell you to solve the problem by introducing an artificial key rather than mapping a composite primary key. While this is, indeed, ideal, one of the premises of O/R mapping is that you, as a developer, often have little control over the database structure.
In situations where a composite key appears just once, I would encourage you to use XDoclet to generate the initial mapping (specifying an @hibernate.id for the identifier class property) and fill in the blanks, using a hand-coded mapping file for those classes.
If, however, you have a composite id class that is repeatedly used in multiple classes throughout the application, there is a way to generate the mapping properly, albeit a bit ugly. Suppose you have a composite Id class, com.acme.data.SkuLineId, with 2 attributes, salesObjectId and sku. Your persistent class would have an attribute of type SkuLineId, possibly named skuLineId.
By specifying a blank @hibernate.id tag for this attribute’s getter in each persistent class that uses the id, you can use the following addition to your Ant script to update the generated mappings with the correct code (all &, <, etc. must be copied verbatim – they aren’t typos):
<replaceregexp match=”<composite-id\s*name="skuLineId"\s*class="com.acme.data.SkuLineId"\s*>\s*</composite-id>”
replace=”<composite-id name="skuLineId" class="com.acme.data.SkuLineId"> <key-property name="salesObjectId" column="sls_obj_id" type="java.lang.Long"/> <key-property name="sku" column="sku" type="java.lang.String"/>
</composite-id>”>
<fileset dir=”${build.classes.dir}”>
<include name=”**/*.hbm.xml”/>
</fileset>
</replaceregexp>
What this code does is search for all hibernate mappings containing a composite id attribute names skuLineId, of type SkuLineId, that doesn’t have any of its details declared, and replaces it with the full mapping. The assumptions are:
- You have used the same composite id in mutliple classes
- That composite id has the same field name in each class
- The columns for each part of the id must be the same for all tables
So this solves the problem for a very limited subset of possible problems, and it is a bit of a hack solution, but it does the job. For other situations, while it would be nice to have other ways to use XDoclet to generate these mappings, I’ve looked extensively and can’t find it. This seems to be the only situation where using XDoclet makes much sense. Even then, it reveals a case where the tools just don’t meet the need. Perhaps JSR175 metadata can bail us out of this mess.
A clarification – by no means am I recommending this approach for widespread adoption. This happens to solve a problem I’m having, and I want to share it. I desperately hope for a better solution other than hand-coding the persistence for these classes and this jumbled mess of XDoclet, Hibernate and Ant regexpreplace.
Hi!
Just asking if you have found some solution to this composite-id XDoclet problem?
I’m currenty hacking it with fake id xdoclet tag and having hibernate-properties-XXX.xml file to merge with composite-id tag in it.