映射枚举
枚举类型是一个常见的Java惯用语,其中类有着(小)数量不变的不可变实例。
1、在JDK5.0中使用枚举
如果使用JDK5.0,可以给类型安全的枚举使用内建的语言支持。例如,Rating类看起来如下:
package auction.model;
public enum Rating{
EXCELLENT, OK, BAD
}
Comment类有这个类型的一个属性:
public class Comment{
...
private Rating rating;
private Item auction;
...
}
2、编写定制的枚举处理程序
现在要介绍的不是最基础的UserType接口,而是EnhanceUserType接口。
public class StringEnumUserType implements EnhancedUserType, ParameterizedType {
private Class<Enum> enumClass;
public void setParameterValues(Properties parameters) {
String enumClassName = parameters.getProperty("enumClassName");
try {
enumClass = ReflectHelper.classForName(enumClassName);
} catch (ClassNotFoundException e) {
throw new HibernateException("Enum class not found", e);
}
}
// //映射Java值类型
public Class returnedClass() {
return enumClass;
}
// 告诉Hibernate要使用什么SQL列类型生成DDL模式
public int[] sqlTypes() {
return new int[] { StringType.INSTANCE.sqlType() };
}
// 这个类型是否可变
public boolean isMutable() {
return false;
}
// 创建值的快照
public Object deepCopy(Object value) throws HibernateException {
return value;
}
// 以序列化的形保存信息的数据的高速缓存
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
// 高速缓存的数据转变为MonetaryAmount的一个实例
public Object assemble(Serializable cached, Object owner)
throws HibernateException {
return cached;
}
// 处理脱管对象状态的合并
public Object replace(Object original, Object target, Object owner)
throws HibernateException {
return original;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y)
return true;
if (null == x || null == y)
return false;
return x.equals(y);
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public Object fromXMLString(String xmlValue) {
return Enum.valueOf(enumClass, xmlValue);
}
public String objectToSQLString(Object value) {
return ‘\‘‘ + ((Enum) value).name() + ‘\‘‘;
}
public String toXMLString(Object value) {
return ((Enum) value).name();
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String name = rs.getString(names[0]);
return rs.wasNull() ? null : Enum.valueOf(enumClass, name);
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (null == value) {
st.setNull(index, StringType.INSTANCE.sqlType());
} else {
st.setString(index, ((Enum) value).name());
}
}
}
3、用XML和注解映射枚举
在XML映射中,首先创建一个定制的类型定义:
<typedef class = "persistence.StringEnumUserType"
name = "rating">
<param name="enumClassName">auction.model.Rating</param>
</typedef>
现在可以在Comment类映射中使用名为rating的类型:
<property name = "rating"
column = "RATING"
type = "rating"
not-null = "true"
update = "false"
access = "field"/>
另一方面,可以依赖Java Persistence提供程序持久化枚举。如果在类型java.lang.Enum中的一个被注解的实体类中有一个属性(例如Comment中的rating),并且它没有标记为@Transient或者transient(Java关键字),Hibernate JPA实现必须毫无怨言地保持该属性为开箱即用;它有一个处理这个的内建类型。这个内建的映射类型在数据库中必须默认为枚举的一种表示法。两种最常见的选择是字符串表示法,就像通过定制类型或者有序表示法与原生的Hibernate实现一样。有序表示法保存选中的枚举选项的位置:例如,1为EXCELLENT,2为OK,3为BAD。数据库列也默认为一个数字列。可以在属性上通过Enumerated注解改变这个默认的枚举映射:
public class Comment{
...
@Enumerated(EnumType.STRING)
@Column(name = "RATING", nullable = false, updatable = false)
private Rating rating;
}
现在已经切换到了基于字符串的表示法,实际上是与你的定制类型可以读写的相同的表示法。也可以使用JPA XML描述符:
<entity class="auction.model.Item" access="PROPERTY">
<attributes>
...
<basic name = "rating">
<column name = "RATING" nullable = "false" updatable = "false"/>
<enumerated>STRING</enumerated>
</basic>
</attributes>
</entity>
4、用定制映射类型查询
你可能遇到的进一步问题是在Hibernate查询中使用被枚举的类型。例如,考虑获取所有等级为"bad"的评语的HQL格式的下列查询:
Query q =
session.createQuery(
"from Comment c where c.rating = auction.model.Rating.BAD"
);
如果把枚举持久化为字符串,虽然这个查询也有效(查询解析器用枚举值作为常量),但是如果选择了有序表示法,它就不起作用了。必须使用一个绑定参数,并对比较式通过编程来设置等级值:
Query q =
session.createQuery("from Comment c where c.rating = :rating");
Properties params = new Properties();
params.put("enumClassname",
"auction.model.Rating");
q.setParameter("rating",Rating.BAD,
Hibernate.custom(StringEnumUserType.class, params)
);
本例的最后一行使用静态的辅助方法Hibernate.custom(),来把定制的映射类型转化为Hibernate Type;这是告诉Hibernate有关枚举映射,以及如何处理Rating.BAD值的一种简单方法。注意,你还必须告诉Hibernate有关被参数化的类型可能需要的任何初始化属性。Hibernate实战_笔记34(映射枚举、实现EnhanceUserType接口),布布扣,bubuko.com
Hibernate实战_笔记34(映射枚举、实现EnhanceUserType接口)