2

我们的系统中有一个存储资源键/值对的表。有两列存储值;一个 VARCHAR 列用于较小的值,一个 CLOB 用于较大的值。在 Java 端,它们被实例化为两个类之一,一个 StandardResourceBundleValue 或一个 LargeResourceBundleValue,并且在一个表中使用一个鉴别器列来区分它们:

<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>

这是有趣的部分:如果键的值开始时很小(并作为 StandardResourceBundleValue 持久化)然后值变为大于 VARCHAR,我们需要一种将其转换为 StandardResourceBundleValue 的方法。发生这种情况的代码不能只删除 StandardResourceBundleValue 并创建 LargeResourceBundleValue,因为这会导致违反约束。

我们想做的是为那个鉴别器列定义一个属性,所以基类可以有一个方法来改变对象中的值,所以当它再次持久化时,它会将值保存在 CLOB 中。

<property name="resourceType" type="string">
    <column name="RESOURCE_TYPE"/>
</property>    

当我尝试构建表时,出现以下错误:

实体映射中的重复列:com.foo.resourcebundle.LargeResourceBundleValue 列:RESOURCE_TYPE(应使用 insert="false" update="false" 进行映射)

显然它不明白我想要做什么,但应该有一种方法是有道理的。那么如何将鉴别器字段公开为属性?

谢谢。

4

1 回答 1

2

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 when setMessageValue() is called, based on the length of the new value.

于 2012-01-11T21:53:06.190 回答