Hibernate如何映射枚举类型

问题:

Java BO类Gender是枚举类型,想在数据库中存成字符串格式,如何编写hbm.xml?

  1. public enum Gender{
  2.   UNKNOWN(“Unknown”),
  3.   MALE(“Male”),
  4.   FEMALE(“Female”);
  5.   private String key;
  6.   private Gender(final String key) {
  7.     this.key = key;
  8.   }
  9.   public getGender(String key) {
  10.     for (Gender gender : Gender.values()) {
  11.       if (key.euqals(gender.getKey()))
  12.         return gender;
  13.     }
  14.     throw new NoSuchElementException(key);
  15.   }
  16. }

使用UserType:

  1. public class GenderUserType implements UserType {
  2.     private static int[] typeList = {  Types.VARCHAR};
  3.   /*
  4.    * Return the SQL type codes for the columns mapped by this type.
  5.    * The codes are defined on <tt>java.sql.Types</tt>. */
  6.   /**设置和Gender类的sex属性对应的字段的SQL类型 */
  7.   public int[] sqlTypes() {
  8.      return typeList;
  9.   }
  10.   /*The class returned by <tt>nullSafeGet()</tt>.*/
  11.   /** 设置GenderUserType所映射的Java类:Gender类 */
  12.   public Class returnedClass() {
  13.      return Gender.class;
  14.   }
  15.   /** 指明Gender类是不可变类 */
  16.   public boolean isMutable() {
  17.      return false;
  18.   }
  19.   /*
  20.   * Return a deep copy of the persistent state, stopping at entities and at
  21.   * collections. It is not necessary to copy immutable objects, or null
  22.   * values, in which case it is safe to simply return the argument.
  23.   */
  24.   /** 返回Gender对象的快照,由于Gender类是不可变类, 因此直接将参数代表的Gender对象返回 */
  25.   public Object deepCopy(Object value) {
  26.     return (Gender)value;
  27.   }
  28.   /** 比较一个Gender对象是否和它的快照相同 */
  29.   public boolean equals(Object x, Object y) {
  30.     //由于内存中只可能有两个静态常量Gender实例,
  31.     //因此可以直接按内存地址比较
  32.     return (x == y);
  33.   }
  34.   public int hashCode(Object x){
  35.      return x.hashCode();
  36.   }
  37.   /*
  38.   * Retrieve an instance of the mapped class from a JDBC resultset. Implementors
  39.   * should handle possibility of null values.
  40.   */
  41.   /** 从JDBC ResultSet中读取key,然后返回相应的Gender实例 */
  42.   public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
  43.                               throws HibernateException, SQLException{
  44.      //从ResultSet中读取key
  45.      String sex = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
  46.      if (sex == null) { return null; }
  47.      //按照性别查找匹配的Gender实例
  48.      try {
  49.         return Gender.getGender(sex);
  50.      }catch (java.util.NoSuchElementException e) {
  51.         throw new HibernateException(“Bad Gender value: ” + sex, e);
  52.      }
  53.  }
  54.  /*
  55.   * Write an instance of the mapped class to a prepared statement. Implementors
  56.   * should handle possibility of null values.
  57.   * A multi-column type should be written to parameters starting from <tt>index</tt>.
  58.   */
  59.   /** 把Gender对象的key属性添加到JDBC PreparedStatement中 */
  60.   public void nullSafeSet(PreparedStatement st, Object value, int index)
  61.                                throws HibernateException, SQLException{
  62.     String sex = null;
  63.     if (value != null)
  64.         sex = ((Gender)value).getKey();
  65.     Hibernate.String.nullSafeSet(st, sex, index);
  66.  }
  67.  /*
  68.   * Reconstruct an object from the cacheable representation. At the very least this
  69.   * method should perform a deep copy if the type is mutable. (optional operation)
  70.   */
  71.   public Object assemble(Serializable cached, Object owner){
  72.      return cached;
  73.   }
  74.   /*
  75.      * Transform the object into its cacheable representation. At the very least this
  76.      * method should perform a deep copy if the type is mutable. That may not be enough
  77.      * for some implementations, however; for example, associations must be cached as
  78.      * identifier values. (optional operation)
  79.    */
  80.    public Serializable disassemble(Object value) {
  81.          return (Serializable)value;
  82.    }
  83.  /*
  84.   * During merge, replace the existing (target) value in the entity we are merging to
  85.   * with a new (original) value from the detached entity we are merging. For immutable
  86.   * objects, or null values, it is safe to simply return the first parameter. For
  87.   * mutable objects, it is safe to return a copy of the first parameter. For objects
  88.   * with component values, it might make sense to recursively replace component values.
  89.  */
  90.   public Object replace(Object original, Object target, Object owner){
  91.         return original;
  92.   }
  93. }

然后再hbm.xml中定义映射关系:

  1. <hibernate-mapping package=”” default-lazy=”true” default-cascade=”save-update,merge,persist”>
  2.     <typedef name=”Gender” class=”com.alpha.hibernate.GenderUserType”>
  3.         <property name=”gender” type=”Gender”>
  4.                 <column name=”GENDER” not-null=”true”>
  5.                 </column>
  6.         </property>

 

延伸:

为每个枚举类型定义一个UserType是比较麻烦的,可以定义一个抽象类。

例如扩展下例即可适用于所有保存为index的枚举类型

  1. public abstract class OrdinalEnumUserType<E extends Enum<E>> implements UserType {
  2.     protected Class<E> clazz;
  3.     protected OrdinalBasedEnumUserType(Class<E> clazz) {
  4.         this.clazz = clazz;
  5.     }
  6.     private static final int[] SQL_TYPES = {Types.NUMERIC};
  7.     public int[] sqlTypes() {
  8.         return SQL_TYPES;
  9.     }
  10.     public Class<?> returnedClass() {
  11.         return clazz;
  12.     }
  13.     public E nullSafeGet(ResultSet resultSet, String[] names, Object owner)
  14.                              throws HibernateException, SQLException {
  15.         //Hibernate.STRING.nullSafeGet(rs, names[0])
  16.         int index = resultSet.getInt(names[0]);
  17.         E result = null;
  18.         if (!resultSet.wasNull()) {
  19.             result = clazz.getEnumConstants()[index];
  20.         }
  21.         return result;
  22.     }
  23.     public void nullSafeSet(PreparedStatement preparedStatement,
  24.           Object value,int index) throws HibernateException, SQLException {
  25.         if (null == value) {
  26.             preparedStatement.setNull(index, Types.NUMERIC);
  27.         } else {
  28.             //Hibernate.String.nullSafeSet(st, sex, index);
  29.             preparedStatement.setInt(index, ((E)value).ordinal());
  30.         }
  31.     }
  32.     public Object deepCopy(Object value) throws HibernateException{
  33.         return value;
  34.     }
  35.     public boolean isMutable() {
  36.         return false;
  37.     }
  38.     public Object assemble(Serializable cached, Object owner)
  39. throws HibernateException {
  40.          return cached;
  41.     }
  42.     public Serializable disassemble(Object value) throws HibernateException {
  43.         return (Serializable)value;
  44.     }
  45.     public Object replace(Object original, Object target, Object owner)
  46. throws HibernateException {
  47.         return original;
  48.     }
  49.     public int hashCode(Object x) throws HibernateException {
  50.         return x.hashCode();
  51.     }
  52.     public boolean equals(Object x, Object y) throws HibernateException {
  53.         if (x == y)
  54.             return true;
  55.         if (null == x || null == y)
  56.             return false;
  57.         return x.equals(y);
  58.     }
  59. }

标签