Hibernate提供了客户化映射类型接口,允许用户以编程的方式创建自定义的映射类型,以便把持久化类的任意类型的属性映射到数据库中.例1的PhoneUserType实现了net.sf.hibernate.UserType接口,它能够把Customer类的Integer类型的phone属性映射到CUSTOMER表的VARCHAR类型的PHONE字段.
例1:
package mypack;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
/**
* @author lfm
*
*/
public class PhoneUserType implements UserType {
private static final int[] SQL_TYPES = {Types.VARCHAR};
public int[] sqlTypes() {
// TODO 自动生成方法存根
return SQL_TYPES;
}
public Class returnedClass() {
// TODO 自动生成方法存根
return Integer.class;
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
// TODO 自动生成方法存根
if(resultSet.wasNull())
return null;
String phone = resultSet.getString(names[0]);
return new Integer(phone);
}
public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {
// TODO 自动生成方法存根
if(value== null)
arg0.setNull(index, Types.VARCHAR);
else {
String phone = ((Integer)value).toString();
statement.setString(index, phone);
}
}
public Object deepCopy(Object value) throws HibernateException {
// TODO 自动生成方法存根
return value;
}
public boolean equals(Object x, Object y) throws HibernateException {
// TODO 自动生成方法存根
if(x== y)
return true;
if(x== null || y== null)
return false;
return x.equals(y);
}
public boolean isMutable() {
// TODO 自动生成方法存根
return false;
}
}
PhoneUserType实现了net.sf.hibernate.UserType接口中的所有方法,下面解释这些方法的作用.
(1)设置CUSTOMERS表的PHONE字段SQL类型,它是VARCHAR类型:
private static final int[] SQL_TYPES = {Types.VARCHAR};
public int[] sqlTypes() {return SQL_TYPES;}
(2)设置Customer类的phone属性的Java类型,它是Integer类型:
public CLass returnedClass() {return Integer.class;}
(3)Hibernate调用isMutable()方法来了解Integer类是否是可变类.本例的Integer类是不可变类,因此返回false.Hibernate处理不可变属性类型的属性时,会采取一些性能优化措施.
public boolean isMutable() {return false;}
(4)Hibernate调用deepCopy(Object value)方法来生成phone属性的快照.deepCopy()方法的value参数代表Integer类型的phone属性.由于Integer类是不可变类,因此本方法直接返回参数:
public Object deepCopy(Object value) {
return value;
}
对于可变类,必须返回参数的拷贝值.后面会说.
(5)Hibernate调用equals(Object x, Object y)方法类比较Customer类的phone属性的当前值是否和它的快照相同.该方法的一个参数代表phone属性的当前值,一个参数代表由deepCopy()方法生成的phone属性的快照:
public boolean equals(Object x, Object y) {
if(x== y)
return true;
if(x== null || y== null)
return false;
return x.equals(y);
}
(6)当Hibernate从数据库加载Customer对象时,调用nullSafeGet()方法类取得phone属性值.参数resultSet为JDBC查询结果集,参数names为存放了表字段名的数组,此处为{"PHONE"},参数owner代表phone属性的宿主,此处为Customer对象.
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException,SQLException {
if(resultSet.wasNull()) return null;
String phone = resultSet.getString(names[0]);
return new Integer(phone);
}
在nullSafeGet方法中,先从ResultSet从读取PHONE字段的值,然后把它转换为Integer对象,最后将它作为phone属性值返回.
(7)当Hibernate把Customer对象持久化到数据库中时,调用nullSafeSet()方法来把phone属性添加到INSERT SQL语句中.statement参数包含了预定义的INSERT SQL语句,参数value代表phone属性,参数index代表把phone属性插入到INSERT SQL语句中的位置:
public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {
if(value == null) {
statement.setNull(index, Types.VARCHAR);
}else{
String phone = ((Integer)value).toString();
statement.setString(index, phone);
}
}
在nullSafeSet()方法中,参数value代表phone属性.因此,先把Integer类型的value转换为String类型,然后把它添加到JDBC Statement中.
定义了PhoneUserType类后,在Customer.hbm.xml中按如下方式映射Customer类的phone属性:
<property name="name" type="mypack.PhoneUserType">
<column name="phone" length="8"/>
</property>
PhoneUserType不仅仅可以用来映射phone属性,事实上,它能够把持久化类的任何一个Integer类型的属性映射到数据库中VARCHAR类型的字段.