I was wondering if there is a way to do Hibernate mapping for the following. My two days spent on this say there isn't.
There are two tables, having one to many
relationship.
+---------------------+ +-----------------+
| versioned_entity | | basic_entity |
+---------------------+ +-----------------+
| fk_BasicEntityId | * 1 | id |
| version |-------| active_version |
| ... | | ... |
+---------------------+ +-----------------+
Hibernate mapping:
<class name="my.VersionedEntity" table="versioned_entity">
<composite-id>
<key-many-to-one name="basicEntity" column="fk_BasicEntityId"/>
<key-property name="version"/>
</composite-id>
...
</class>
<class name="my.BasicEntity" table="basic_entity">
<id name="id">
<property name="activeVersion" not-null="true">
<column name="active_version"/>
</property>
...
</class>
Brief explanation: fk_BasicEntityId
is a foreign key pointing to basic_entity.id
. An entry in versioned_entity
can be identified by its foreign key and version
(there can be many versions having same fk_BasicEntityId
). active_version
is a number pointing to one of versioned_entity
entries and tells which version is "active". Hope that's clear enough.
Now the problem I am solving is that I need quick access in Java like this:
my.BasicEntity basic = my.BasicEntityDAO.get();
my.VersionedEntity activeVersion = basic.getActiveVersionedEntity();
The current implementation is done in Java and simply iterates over all versioned entities of given basic entity and checks if its version matches with active version. Needless to say, this doesn't scale and results performance problems.
So I went on to move this onto database level. Looks easy? So I thought! I went on and added following into Hibernate mapping of basic_entity:
<many-to-one name="activeVersionedEntity" not-null="false" insert="false" update="false">
<column name="id" unique="true" not-null="true"/>
<column name="activeVersion"/>
</many-to-one>
The double column is required here for versioned_entity
has composite key.
Unfortunately, this doesn't work - JVM dies without a trace when a call to be.getActiveVersionedEntity()
is invoked (on colleague's machine it throws StackOverflowError inside Hibernate). I suspect this happens because "id" is also an identifier, as I have very similar mapping for the same class where column is not an identifier and this works correctly.
I could probably do this with HQL, but that would require me to move this method into the DAO class which is particularly awkward as would require changes in API (not an option). Using DAO call inside my.BasicEntity::getActiveVersionedEntity()
is another big no-no: I can't mix up different abstraction layers. Another way of solving this would be looking into Interceptors/events, however this also probably one of those options which beat the purpose of the framework (I shouldn't care about low level things like this, do I?).
I am running Hibernate version: 3.2.7GA / Spring 2.5.6. The documentation is unbelievably poor - I have looked at three different Hibernate books, online documentation, forums, etc.
Any help is appreciated.