`
gqzyyxh
  • 浏览: 9381 次
  • 性别: Icon_minigender_1
  • 来自: 常州
文章分类
社区版块
存档分类
最新评论

Hibernate高级映射技术(一)自定义数据类型StringList (转载用于收藏)

阅读更多
转载于:http://ajava.org/course/open/14003.html   
    核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式

    我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式的设计原则,但在性能和编码复杂度上确实最低的。
这样如果用Hibernate的String类型来映射,就会得到一个长字符串,每次必须按;分隔后才能使用,这样代码就很冗余。
    幸好Hibernate有自定义数据类型的支持,只要实现UserType或CompositeUserType接口。不过这两个接口的内容比较复杂,有很多方法需要实现,不能偷懒哦:-)
下    面是我对于用;分隔的字段的自定义数据类型的实现。

package com.willishz.framework.dao.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.hibernate.Hibernate;   
import org.hibernate.HibernateException;   
import org.hibernate.usertype.UserType;   
  
/**  
* 用分隔符分隔的字符串数组.分隔符默认为";"  
* @author willishz  
*/  
public class StringList implements UserType, Serializable {   
  
public StringList() {   
  super();   
}   
  
public StringList(char splitter) {   
  super();   
  this.splitter = splitter;   
}   
  
public StringList(List<String> attributeList) {   
  super();   
  this.attributeList = attributeList;   
}   
  
private List<String> attributeList;   
  
/**  
  * 分隔符  
  */  
private char splitter = SPLITTER;   
  
/**  
  * 分隔符默认为";"  
  */  
private static final char SPLITTER = ';';   
  
private static final int[] SQLTYPES = new int[] { Types.VARCHAR };   
  
public boolean isMutable() {   
  return false;   
}   
  
public int[] sqlTypes() {   
  return SQLTYPES;   
}   
  
public Object assemble(Serializable id, Object obj) throws HibernateException {   
  return null;   
}   
  
/**  
  * 将List类型的数组拼接成字符串  
  * @param attributeList  
  * @return  
  * @throws HibernateException  
  */  
public Object assemble(List<String> attributeList) throws HibernateException {   
  if (attributeList == null) {   
   return null;   
  }   
  StringBuffer asbl = new StringBuffer();   
  asbl.append(attributeList.get(0));   
  for (int i = 1; i < attributeList.size(); i++) {   
   asbl.append(splitter).append(attributeList.get(i));   
  }   
  return asbl.toString();   
}   
  
/**  
  * 自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象  
  *  
  * @param value the object to be cloned, which may be null  
  * @return Object a copy  
  * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)  
  */  
public Object deepCopy(Object value) throws HibernateException {   
  if (value == null) {   
   return null;   
  }   
  ArrayList sourceList = (ArrayList) value;   
  ArrayList targetList = new ArrayList();   
  List<String> _attributeList = new ArrayList<String>();   
  targetList.addAll(sourceList);   
  return targetList;   
}   
  
/**  
  * 自定义数据类型的比较方法  
  *   
  * @param x  
  * @param y  
  * @return boolean  
  * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)  
  */  
public boolean equals(Object x, Object y) throws HibernateException {   
  if (x == y) {   
   return true;   
  }   
  if (x != null && y != null) {   
   List<String> xList = (List<String>) x;   
   List<String> yList = (List<String>) y;   
   if (xList.size() != yList.size()) {   
    return false;   
   }   
   String _x = null;   
   String _y = null;   
   for (int i = 0; i < xList.size(); i++) {   
    _x = xList.get(i);   
    _y = yList.get(i);   
    if (!_x.equalsIgnoreCase(_y)) { // case insensitive   
     return false;   
    }   
   }   
   return true;   
  }   
  return false;   
}   
  
public int hashCode(Object arg0) throws HibernateException {   
  return attributeList.hashCode();   
}   
  
/**  
  * 将以分隔符分隔的字符串解析成一个字符串数组  
  *   
  * @param value  
  * @return  
  */  
public List<String> parse(String value) {   
  if (value == null) {   
   return null;   
  }   
  String[] strs = org.apache.commons.lang.StringUtils.split(value, splitter);   
  List<String> attributeList = new ArrayList<String>();   
  for (int i = 0; i < strs.length; i++) {   
   attributeList.add(strs[i]);   
  }   
  return attributeList;   
}   
  
/**  
  * 从JDBC的ResultSet中读取数据,并将其转换为自定义类型后返回。  
  * 此方法要求对可能出现null的情况做处理。  
  * names中包含了当前自定义类型的映射字段名称。  
  *   
  * @param rs a JDBC result set  
  * @param names the column names  
  * @param owner the containing entity  
  * @return Object  
  * @throws HibernateException  
  * @throws SQLException  
  * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)  
  */  
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);   
  }   
  return null;   
}   
  
/**  
  * 在Hibernate进行数据保存时被调用  
  * 可以通过PreparedStatement将自定义数据写入对应的数据库字段中  
  * names中包含了当前自定义类型的映射字段名称。  
  *  
  * @param st a JDBC prepared statement  
  * @param value the object to write  
  * @param index statement parameter index  
  * @throws HibernateException  
  * @throws SQLException  
  * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)  
  */  
public void nullSafeSet(PreparedStatement pst, Object value, int index)   
throws HibernateException, SQLException {   
  if (value != null) {   
   Hibernate.STRING.nullSafeSet(pst, assemble((List<String>) value), index);   
  } else {   
   Hibernate.STRING.nullSafeSet(pst, value, index);   
  }   
}   
  
public Class returnedClass() {   
  return StringList.class;   
}   
  
public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {   
  return null;   
}   
  
public Serializable disassemble(Object arg0) throws HibernateException {   
  return null;   
}   
}  

Hibernate配置文件的相关内容如下:

<?xml version="1.0"?>  
<!DOCTYPE hibernate-mapping PUBLIC   
"-//Hibernate/Hibernate Mapping DTD//EN"   
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >  
  
<hibernate-mapping package="com.willishz.apocalypse.ebid.domain">  
<class  
  name="User"  
  table="t_user"  
>  
.................   
  <property  
   name="mobiles"  
   column="mobiles"  
   type="com.willishz.framework.dao.usertype.StringList"  
   not-null="false"  
   length="100"  
  />  
.................   
</class>    
</hibernate-mapping>  

Hibernate映射实体文件的相关内容:

package com.willishz.apocalypse.ebid.domain.base;   
  
import java.io.Serializable;   
  
public abstract class User  implements Serializable {   
.................   
    
private java.util.List<String> mobiles;   
    
public java.util.List<String> getMobiles() {   
  return mobiles;   
}   
  
public void setmobiles(java.util.List<String> mobiles) {   
  this.mobiles = mobiles;   
}   
.................   
}   
  
分享到:
评论

相关推荐

    ssh(structs,spring,hibernate)框架中的上传下载

    Tfile的Hibernate映射文件Tfile.hbm.xml放在Tfile .java类文件的相同目录下:  代码 2 领域对象映射文件 1. 2. !DOCTYPE hibernate-mapping PUBLIC 3. "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4. ...

    java面试题

    int和Integer有什么区别? 答:int是java的原始数据类型,Integer是java为int提供的封装类,java为每个原始数据类型都提供了封装类。 String和StringBuffer的区别?... String不是基本数据类型,引用数据类型。 ...

    深入浅出Struts 2 .pdf(原书扫描版) part 1

    如数据类型转换、文件上传和下载、Struts2应用的安全性、调试与性能分析、FreeMarker、Velocily、Ajax,等等。跟随作者一道深入Struts2。聆听大量来之不易的经验之谈。你对Struts2开发框架的理解和应用水平都将更上...

    深入浅出Struts2(附源码)

    作者处处从实战出发,在丰富的示例中直观地探讨了许多实用的技术,如数据类型转换、文件上传和下载、提高Struts 2应用的安全性、调试与性能分析、FreeMarker、Velocity、Ajax,等等。跟随作者一道深入Struts 2,聆听...

    JAVA上百实例源码以及开源项目

     使用Java语言编写的一款用于反映颜色变化的面板,也就是大家熟悉的颜色调色板演示程序。原理是初始化颜色选择按钮,然后为颜色选择按钮增加事件处理事件,最后实例化颜色选择器。 Java二进制IO类与文件复制操作...

    JAVA上百实例源码以及开源项目源代码

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    Java常见面试题208道.docx

    6.String 属于基础的数据类型吗? 7.java 中操作字符串都有哪些类?它们之间有什么区别? 8.String str="i"与 String str=new String(“i”)一样吗? 9.如何将字符串反转? 10.String 类的常用方法都有那些? 11....

    java源码包---java 源码 大量 实例

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    java源码包2

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    java源码包3

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    java源码包4

    ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,...

    成百上千个Java 源码DEMO 4(1-4是独立压缩包)

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

    成百上千个Java 源码DEMO 3(1-4是独立压缩包)

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

    Java学习笔记-个人整理的

    {1.4}数据类型}{23}{section.1.4} {1.4.1}整数与浮点数}{23}{subsection.1.4.1} {1.4.1.1}浮点数原理}{24}{subsubsection.1.4.1.1} {1.4.2}格式化输出浮点数}{24}{subsection.1.4.2} {1.4.3}\texttt {char}}{24...

Global site tag (gtag.js) - Google Analytics