We have a table in our system that stores resource key/value pairs. There are two columns to store the value; a VARCHAR column for smaller values and a CLOB for larger values. On the Java side, they are instantiated into one of two classes, a StandardResourceBundleValue or a LargeResourceBundleValue, and a discriminator column is used to distinguish them in the one table:
<discriminator type="string">
<column name="RESOURCE_TYPE" length="20" index="XIE1CPD_RESOURCE_BUNDLE_L_V"/>
</discriminator>
...
<subclass name="StandardResourceBundleValue" discriminator-value="STANDARD">
<property name="messageValue" type="string" column="STD_MSG_VALUE" length="400"/>
</subclass>
<subclass name="LargeResourceBundleValue" discriminator-value="LARGE">
<property name="messageValue" type="materialized_clob" column="LARGE_MSG_VALUE"/>
</subclass>
Here's the fun part: If the value of a key started out small (and persisted as a StandardResourceBundleValue) then the value changes to one larger than the VARCHAR, we need a way to convert it to a StandardResourceBundleValue. The code this is happening in can't just delete the StandardResourceBundleValue and create a LargeResourceBundleValue, because that's causing constraint violations.
What we would like to do is define a property for that discriminator column, so the base class can have a method that changes that value in the object, so when it's persisted again it will save the value in the CLOB.
<property name="resourceType" type="string">
<column name="RESOURCE_TYPE"/>
</property>
When I try building the table, I get the following error:
Repeated column in mapping for entity: com.foo.resourcebundle.LargeResourceBundleValue column: RESOURCE_TYPE (should be mapped with insert="false" update="false")
Clearly it doesn't understand what I'm trying to do, but it makes sense that there should be a way of doing it. So how do you expose a discriminator field as a property?
Thanks.
You can't do that. An object has a type, and it can't switch from one type to another. That's just how Java works.
I think you just shouldn't have two types of entities here. Why don't you just store the discriminator as a basic enum column, and store/fetch the value of the property in the varchar or clob column based on the value of this enum. Make sure everything is transparently encapsulated into the object, and everything will be easier, even for callers. The enum field could even not be made public. You use it to implement
getMessageValue()
(get the value from the appropriate column), and you change its value whensetMessageValue()
is called, based on the length of the new value.