Hibernate映射自定义数据类型
数据库中存在一个email字段,并允许其中存储多个email地址,各地址之间使用 ; 分割,但是在POJO中,为了便于处理,email定义为一个List对象。
如何将String字段映射为List类型,Hibernate并没有提供原生支持,需要我们实现自己的UserType。
1.数据库定义
DROP
TABLE
t_user_mail;
CREATE TABLE t_user_mail (
id INT NOT NULL AUTO_INCREMENT
, name VARCHAR ( 50 )
, age INT
, email VARCHAR ( 300 )
, PRIMARY KEY (id)
);
CREATE TABLE t_user_mail (
id INT NOT NULL AUTO_INCREMENT
, name VARCHAR ( 50 )
, age INT
, email VARCHAR ( 300 )
, PRIMARY KEY (id)
);
2.
实现了UserType的自定义数据类型类EMailList
package
cn.blogjava.usertype;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class EMailList implements UserType {
private static final char SPLITTER = ' ; ' ;
private static final int [] TYPES = new int [] {Types.VARCHAR};
public int [] sqlTypes() {
// TODO Auto-generated method stub
return TYPES;
}
public Class returnedClass() {
// TODO Auto-generated method stub
return List. class ;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) return true ;
if (x != null & y != null ) {
List xlist = (List)x;
List ylist = (List)y;
if (xlist.size() != ylist.size()) return false ;
for ( int i = 0 ; i < xlist.size(); i ++ ) {
String str1 = (String)xlist.get(i);
String str2 = (String)ylist.get(i);
if ( ! str1.equals(str2)) return false ;
}
return true ;
}
return false ;
}
public int hashCode(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return 0 ;
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String)Hibernate.STRING.nullSafeGet(rs, names[ 0 ]);
if (value != null ) {
return parse(value);
} else {
return null ;
}
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null ) {
String str = assemble((List)value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List)value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}
public boolean isMutable() {
// TODO Auto-generated method stub
return false ;
}
public Serializable disassemble(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
public Object assemble(Serializable arg0, Object arg1)
throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
private String assemble(List emailList) {
StringBuffer strBuf = new StringBuffer();
for ( int i = 0 ; i < emailList.size() - 1 ; i ++ ) {
strBuf.append((String)emailList.get(i)).append(SPLITTER);
}
strBuf.append(emailList.get(emailList.size() - 1 ));
return strBuf.toString();
}
private List parse(String value) {
String[] strs = StringUtils.split(value, SPLITTER);
List emailList = new ArrayList();
for ( int i = 0 ; i < strs.length; i ++ ) {
emailList.add(strs[i]);
}
return emailList;
}
}
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
public class EMailList implements UserType {
private static final char SPLITTER = ' ; ' ;
private static final int [] TYPES = new int [] {Types.VARCHAR};
public int [] sqlTypes() {
// TODO Auto-generated method stub
return TYPES;
}
public Class returnedClass() {
// TODO Auto-generated method stub
return List. class ;
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) return true ;
if (x != null & y != null ) {
List xlist = (List)x;
List ylist = (List)y;
if (xlist.size() != ylist.size()) return false ;
for ( int i = 0 ; i < xlist.size(); i ++ ) {
String str1 = (String)xlist.get(i);
String str2 = (String)ylist.get(i);
if ( ! str1.equals(str2)) return false ;
}
return true ;
}
return false ;
}
public int hashCode(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return 0 ;
}
public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
throws HibernateException, SQLException {
String value = (String)Hibernate.STRING.nullSafeGet(rs, names[ 0 ]);
if (value != null ) {
return parse(value);
} else {
return null ;
}
}
public void nullSafeSet(PreparedStatement st, Object value, int index)
throws HibernateException, SQLException {
if (value != null ) {
String str = assemble((List)value);
Hibernate.STRING.nullSafeSet(st, str, index);
} else {
Hibernate.STRING.nullSafeSet(st, value, index);
}
}
public Object deepCopy(Object value) throws HibernateException {
List sourceList = (List)value;
List targetList = new ArrayList();
targetList.addAll(sourceList);
return targetList;
}
public boolean isMutable() {
// TODO Auto-generated method stub
return false ;
}
public Serializable disassemble(Object arg0) throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
public Object assemble(Serializable arg0, Object arg1)
throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException {
// TODO Auto-generated method stub
return null ;
}
private String assemble(List emailList) {
StringBuffer strBuf = new StringBuffer();
for ( int i = 0 ; i < emailList.size() - 1 ; i ++ ) {
strBuf.append((String)emailList.get(i)).append(SPLITTER);
}
strBuf.append(emailList.get(emailList.size() - 1 ));
return strBuf.toString();
}
private List parse(String value) {
String[] strs = StringUtils.split(value, SPLITTER);
List emailList = new ArrayList();
for ( int i = 0 ; i < strs.length; i ++ ) {
emailList.add(strs[i]);
}
return emailList;
}
}
3.
配置文件TUserMail.hbm.xml
<?xml version
=
"
1.0
"
?>
<!DOCTYPE hibernate-mapping PUBLIC " -//Hibernate/Hibernate Mapping DTD 3.0//EN "
" http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd " >
<hibernate-mapping>
<!--
Auto-generated mapping file from
the hibernate.org cfg2hbm engine
-->
<class name = " cn.blogjava.usertype.TUserMail " table = " t_user_mail " catalog = " sample " >
<id name = " id " type = " integer " >
<column name = " id " />
<generator class = " native " />
</id>
<property name = " name " type = " string " >
<column name = " name " length = " 50 " />
</property>
<property name = " age " type = " integer " >
<column name = " age " />
</property>
<property name = " email " type = " cn.blogjava.usertype.EMailList " >
<column name = " email " length = " 300 " />
</property>
</class>
</hibernate-mapping>
<!DOCTYPE hibernate-mapping PUBLIC " -//Hibernate/Hibernate Mapping DTD 3.0//EN "
" http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd " >
<hibernate-mapping>
<!--
Auto-generated mapping file from
the hibernate.org cfg2hbm engine
-->
<class name = " cn.blogjava.usertype.TUserMail " table = " t_user_mail " catalog = " sample " >
<id name = " id " type = " integer " >
<column name = " id " />
<generator class = " native " />
</id>
<property name = " name " type = " string " >
<column name = " name " length = " 50 " />
</property>
<property name = " age " type = " integer " >
<column name = " age " />
</property>
<property name = " email " type = " cn.blogjava.usertype.EMailList " >
<column name = " email " length = " 300 " />
</property>
</class>
</hibernate-mapping>
4.
在hibernate.cfg.xml载入TUserMail.hbm.xml
<?xml version
=
"
1.0
"
encoding
=
"
UTF-8
"
?>
<!DOCTYPE hibernate-configuration PUBLIC
" -//Hibernate/Hibernate Configuration DTD 3.0//EN "
" http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd " >
<hibernate-configuration>
<session-factory>
<property name = " hibernate.connection.driver_class " >com.mysql.jdbc.Driver</property>
<property name = " hibernate.connection.password " > 1234 </property>
<property name = " hibernate.connection.url " >jdbc:mysql://localhost: 3306 /sample</property>
<property name = " hibernate.connection.username " >root</property>
<property name = " hibernate.dialect " >org.hibernate.dialect.MySQLDialect</property>
<mapping resource = " cn/blogjava/start/TUser.hbm.xml " />
<mapping resource = " cn/blogjava/usertype/TUserMail.hbm.xml " />
</session-factory>
</hibernate-configuration>
<!DOCTYPE hibernate-configuration PUBLIC
" -//Hibernate/Hibernate Configuration DTD 3.0//EN "
" http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd " >
<hibernate-configuration>
<session-factory>
<property name = " hibernate.connection.driver_class " >com.mysql.jdbc.Driver</property>
<property name = " hibernate.connection.password " > 1234 </property>
<property name = " hibernate.connection.url " >jdbc:mysql://localhost: 3306 /sample</property>
<property name = " hibernate.connection.username " >root</property>
<property name = " hibernate.dialect " >org.hibernate.dialect.MySQLDialect</property>
<mapping resource = " cn/blogjava/start/TUser.hbm.xml " />
<mapping resource = " cn/blogjava/usertype/TUserMail.hbm.xml " />
</session-factory>
</hibernate-configuration>
5.
测试类HibernateTest.java
package
cn.blogjava.usertype;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class HibernateTest extends TestCase {
Session session = null ;
/**
* JUnit中的setUp方法在TestCase初始化的时候会自动调用
* 一般用于初始化公用资源
*/
protected void setUp() {
try {
/**
* 可以采用hibernate.properties或者hibernate.cfg.xml
* 配置文件的初始化代码
*
* 采用hibernate.properties
* Configuration config = new Configuration();
* config.addClass(TUser.class);
*/
// 采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异
// 1.Configuration的初始化方式
// 2.xml
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用
* 一般用于释放资源
*/
protected void tearDown() {
try {
session.close();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 对象持久化测试(Insert方法)
*/
public void testInsert() {
Transaction tran = null ;
try {
tran = session.beginTransaction();
TUserMail user = new TUserMail();
user.setName( " byf " );
List list = new ArrayList();
list.add( " [email protected] " );
list.add( " [email protected] " );
user.setEmail(list);
session.save(user);
session.flush();
tran.commit();
Assert.assertEquals(user.getId().intValue() > 0 , true );
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
Assert.fail(e.getMessage());
if (tran != null ) {
try {
tran.rollback();
} catch (Exception e1) {
// TODO: handle exception
e1.printStackTrace();
}
}
}
}
/**
* 对象读取测试(Select方法)
*/
public void testSelect(){
String hql = " from TUserMail where name='byf' " ;
try {
List userList = session.createQuery(hql).list();
TUserMail user = (TUserMail)userList.get( 0 );
List mailList = user.getEmail();
Assert.assertEquals((String)mailList.get( 0 ), " [email protected] " );
Assert.assertEquals((String)mailList.get( 1 ), " [email protected] " );
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public class HibernateTest extends TestCase {
Session session = null ;
/**
* JUnit中的setUp方法在TestCase初始化的时候会自动调用
* 一般用于初始化公用资源
*/
protected void setUp() {
try {
/**
* 可以采用hibernate.properties或者hibernate.cfg.xml
* 配置文件的初始化代码
*
* 采用hibernate.properties
* Configuration config = new Configuration();
* config.addClass(TUser.class);
*/
// 采用hibernate.cfg.xml配置文件,与上面的方法对比,两个差异
// 1.Configuration的初始化方式
// 2.xml
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
session = sessionFactory.openSession();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* JUnit中的tearDown方法在TestCase执行完毕的时候会自动调用
* 一般用于释放资源
*/
protected void tearDown() {
try {
session.close();
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 对象持久化测试(Insert方法)
*/
public void testInsert() {
Transaction tran = null ;
try {
tran = session.beginTransaction();
TUserMail user = new TUserMail();
user.setName( " byf " );
List list = new ArrayList();
list.add( " [email protected] " );
list.add( " [email protected] " );
user.setEmail(list);
session.save(user);
session.flush();
tran.commit();
Assert.assertEquals(user.getId().intValue() > 0 , true );
} catch (HibernateException e) {
// TODO: handle exception
e.printStackTrace();
Assert.fail(e.getMessage());
if (tran != null ) {
try {
tran.rollback();
} catch (Exception e1) {
// TODO: handle exception
e1.printStackTrace();
}
}
}
}
/**
* 对象读取测试(Select方法)
*/
public void testSelect(){
String hql = " from TUserMail where name='byf' " ;
try {
List userList = session.createQuery(hql).list();
TUserMail user = (TUserMail)userList.get( 0 );
List mailList = user.getEmail();
Assert.assertEquals((String)mailList.get( 0 ), " [email protected] " );
Assert.assertEquals((String)mailList.get( 1 ), " [email protected] " );
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
Assert.fail(e.getMessage());
}
}
}
运行测试代码,观察数据库中,可以发现email地址信息已经以";"分隔的形式保存。同时,在数据读取时,我们也无需面对原始的";"分隔字符串,转而只需要处理List类型数据即可。