Conditional mapping in Hibernate 3.0?
How to create mapping in hibernate that depends on the type property, insert/retrieve the data into/from proper column.
Structure: 开发者_StackOverflow社区
TABLE COLUMNS:
|TYPE | CHARACTER | DATE | TIME | NUMERIC|
POJO:
class Pojo {
private int type;
private Object data;
...
}
Examples:
Insert/Update
If the type is 1 we input the value to column CHARACTERSelect
If the type is 2 we get the value from column NUMERIC
TIP: The structure where we have two columns and we PIVOT the result is not a option for this case.
The solution that i have choose for this is table per class hierarchy mapping with an integer discriminator.
I have created a base abstract generic class that store the object
public abstract class ValueBase<T> {
private Long id;
private int valueType;
private T value;
public T getValue(){
return value;
}
public void setValue(T value){
this.value = value;
}
protected void setValueType(int valueType) {
this.valueType = valueType;
}
public int getValueType(){
return this.valueType;
}
private void setID(Long id) {
this.id = id;
}
public int getID(){
return this.id;
}
}
For Type management i have created and interface, but there is possible to enumeration using the encapsulation presented by Arthur.
public interface IValueTypes() {
public static final int NONE = -1;
public static final int NUMERIC = 0;
public static final int CHARACTER = 1;
public static final int DATE = 2;
public static final int TIME = 3;
public static final int BOOLEAN = 4;
}
The for each type I have created class
public class NumericType extedns ValueBase<BigDecinal> {
public NumericType(){
super();
setValueType(IValueTypes.NUMERIC);
}
}
public class CharacterType extedns ValueBase<String> {
public NumericType(){
super();
setValueType(IValueTypes.CHARACTER);
}
}
TIP: To allow use the a number as discriminator value we need to specify it first for the class that we are mapping, because by default is used class name [String] and i we try to use the numeric discriminator for subclass mapping we will get a hibernate error say that there is some type mismatch.
<class name="TestValue" table="TestValues" schema="TEST" abstract="true" discriminator-value="-1">
<id name="id" type="java.lang.Long">
<column name="VALUE_ID" precision="22" scale="0" />
<generator class="native"/>
</id>
<discriminator column="TYPE_VALUE" not-null="false" type="integer"/>
<subclass discriminator-value="0" name="NumericType">
<property name="value" type="java.math.BigDecimal" column="NUMERIC" not-null="false"/>
</subclass>
<subclass discriminator-value="1" name="CharacterType">
<property name="value" type="java.lang.String" column="CHARACTER" not-null="false"/>
</subclass>
</class>
While we retrieve the object from database is always in given typed class that we can operate easily on it, and we use one place to save them by saving the base class.
This kind of behavior is accomplished by using encapsulation. For instance, i have a String (Y/N) column in database (INSERT/UPDATE) which is encapsulated by a boolean (SELECT) as follows
public class SomeEntity {
private boolean checked;
private boolean isChecked() {
return this.checked;
}
public void setChecked(boolean checked) {
this.checked = checked;
}
public String getCheckedAsString() {
return checked ? "Y" : "N";
}
public void setCheckedAsString(String checked) {
this.checked = checked.equals("Y") ? true : false;
}
}
Your mapping goes here
<property name="checkedAsString" type="string" column="CHECKED"/>
This strategy is explained here I have used, besides conversion, as a workaround To allow String Java keywords To be used as Enum. See here
精彩评论