Hibernate高级映射技术(一)自定义数据类型StringList (转)

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

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

       1. package com.willishz.framework.dao.usertype;  
       2.  
       3. import java.io.Serializable;  
       4. import java.sql.PreparedStatement;  
       5. import java.sql.ResultSet;  
       6. import java.sql.SQLException;  
       7. import java.sql.Types;  
       8. import java.util.ArrayList;  
       9. import java.util.List;  
      10.  
      11. import org.hibernate.Hibernate;  
      12. import org.hibernate.HibernateException;  
      13. import org.hibernate.usertype.UserType;  
      14.  
      15. /** 
      16.  * 用分隔符分隔的字符串数组.分隔符默认为";" 
      17.  * @author willishz 
      18.  */ 
      19. public class StringList implements UserType, Serializable {  
      20.  
      21.  public StringList() {  
      22.   super();  
      23.  }  
      24.  
      25.  public StringList(char splitter) {  
      26.   super();  
      27.   this.splitter = splitter;  
      28.  }  
      29.  
      30.  public StringList(List<String> attributeList) {  
      31.   super();  
      32.   this.attributeList = attributeList;  
      33.  }  
      34.  
      35.  private List<String> attributeList;  
      36.  
      37.  /** 
      38.   * 分隔符 
      39.   */ 
      40.  private char splitter = SPLITTER;  
      41.  
      42.  /** 
      43.   * 分隔符默认为";" 
      44.   */ 
      45.  private static final char SPLITTER = ';';  
      46.  
      47.  private static final int[] SQLTYPES = new int[] { Types.VARCHAR };  
      48.  
      49.  public boolean isMutable() {  
      50.   return false;  
      51.  }  
      52.  
      53.  public int[] sqlTypes() {  
      54.   return SQLTYPES;  
      55.  }  
      56.  
      57.  public Object assemble(Serializable id, Object obj) throws HibernateException {  
      58.   return null;  
      59.  }  
      60.  
      61.  /** 
      62.   * 将List类型的数组拼接成字符串 
      63.   * @param attributeList 
      64.   * @return 
      65.   * @throws HibernateException 
      66.   */ 
      67.  public Object assemble(List<String> attributeList) throws HibernateException {  
      68.   if (attributeList == null) {  
      69.    return null;  
      70.   }  
      71.   StringBuffer asbl = new StringBuffer();  
      72.   asbl.append(attributeList.get(0));  
      73.   for (int i = 1; i < attributeList.size(); i++) {  
      74.    asbl.append(splitter).append(attributeList.get(i));  
      75.   }  
      76.   return asbl.toString();  
      77.  }  
      78.  
      79.  /** 
      80.   * 自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象 
      81.   * 
      82.   * @param value the object to be cloned, which may be null 
      83.   * @return Object a copy 
      84.   * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) 
      85.   */ 
      86.  public Object deepCopy(Object value) throws HibernateException {  
      87.   if (value == null) {  
      88.    return null;  
      89.   }  
      90.   ArrayList sourceList = (ArrayList) value;  
      91.   ArrayList targetList = new ArrayList();  
      92.   List<String> _attributeList = new ArrayList<String>();  
      93.   targetList.addAll(sourceList);  
      94.   return targetList;  
      95.  }  
      96.  
      97.  /** 
      98.   * 自定义数据类型的比较方法 
      99.   *  
     100.   * @param x 
     101.   * @param y 
     102.   * @return boolean 
     103.   * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object) 
     104.   */ 
     105.  public boolean equals(Object x, Object y) throws HibernateException {  
     106.   if (x == y) {  
     107.    return true;  
     108.   }  
     109.   if (x != null && y != null) {  
     110.    List<String> xList = (List<String>) x;  
     111.    List<String> yList = (List<String>) y;  
     112.    if (xList.size() != yList.size()) {  
     113.     return false;  
     114.    }  
     115.    String _x = null;  
     116.    String _y = null;  
     117.    for (int i = 0; i < xList.size(); i++) {  
     118.     _x = xList.get(i);  
     119.     _y = yList.get(i);  
     120.     if (!_x.equalsIgnoreCase(_y)) { // case insensitive  
     121.      return false;  
     122.     }  
     123.    }  
     124.    return true;  
     125.   }  
     126.   return false;  
     127.  }  
     128.  
     129.  public int hashCode(Object arg0) throws HibernateException {  
     130.   return attributeList.hashCode();  
     131.  }  
     132.  
     133.  /** 
     134.   * 将以分隔符分隔的字符串解析成一个字符串数组 
     135.   *  
     136.   * @param value 
     137.   * @return 
     138.   */ 
     139.  public List<String> parse(String value) {  
     140.   if (value == null) {  
     141.    return null;  
     142.   }  
     143.   String[] strs = org.apache.commons.lang.StringUtils.split(value, splitter);  
     144.   List<String> attributeList = new ArrayList<String>();  
     145.   for (int i = 0; i < strs.length; i++) {  
     146.    attributeList.add(strs[i]);  
     147.   }  
     148.   return attributeList;  
     149.  }  
     150.  
     151.  /** 
     152.   * 从JDBC的ResultSet中读取数据,并将其转换为自定义类型后返回。 
     153.   * 此方法要求对可能出现null的情况做处理。 
     154.   * names中包含了当前自定义类型的映射字段名称。 
     155.   *  
     156.   * @param rs a JDBC result set 
     157.   * @param names the column names 
     158.   * @param owner the containing entity 
     159.   * @return Object 
     160.   * @throws HibernateException 
     161.   * @throws SQLException 
     162.   * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object) 
     163.   */ 
     164.  public Object nullSafeGet(ResultSet rs, String[] names, Object owner)  
     165.  throws HibernateException, SQLException {  
     166.   String value = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);  
     167.   if (value != null) {  
     168.    return parse(value);  
     169.   }  
     170.   return null;  
     171.  }  
     172.  
     173.  /** 
     174.   * 在Hibernate进行数据保存时被调用 
     175.   * 可以通过PreparedStatement将自定义数据写入对应的数据库字段中 
     176.   * names中包含了当前自定义类型的映射字段名称。 
     177.   * 
     178.   * @param st a JDBC prepared statement 
     179.   * @param value the object to write 
     180.   * @param index statement parameter index 
     181.   * @throws HibernateException 
     182.   * @throws SQLException 
     183.   * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object) 
     184.   */ 
     185.  public void nullSafeSet(PreparedStatement pst, Object value, int index)  
     186.  throws HibernateException, SQLException {  
     187.   if (value != null) {  
     188.    Hibernate.STRING.nullSafeSet(pst, assemble((List<String>) value), index);  
     189.   } else {  
     190.    Hibernate.STRING.nullSafeSet(pst, value, index);  
     191.   }  
     192.  }  
     193.  
     194.  public Class returnedClass() {  
     195.   return StringList.class;  
     196.  }  
     197.  
     198.  public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {  
     199.   return null;  
     200.  }  
     201.  
     202.  public Serializable disassemble(Object arg0) throws HibernateException {  
     203.   return null;  
     204.  }  
     205. } 

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

       1. <?xml version="1.0"?> 
       2. <!DOCTYPE hibernate-mapping PUBLIC  
       3.  "-//Hibernate/Hibernate Mapping DTD//EN"  
       4.  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > 
       5.  
       6. <hibernate-mapping package="com.willishz.apocalypse.ebid.domain"> 
       7.  <class 
       8.   name="User" 
       9.   table="t_user" 
      10.  > 
      11.  .................  
      12.   <property 
      13.    name="mobiles" 
      14.    column="mobiles" 
      15.    type="com.willishz.framework.dao.usertype.StringList" 
      16.    not-null="false" 
      17.    length="100" 
      18.   /> 
      19.  .................  
      20.  </class>   
      21. </hibernate-mapping> 

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

       1. package com.willishz.apocalypse.ebid.domain.base;  
       2.  
       3. import java.io.Serializable;  
       4.  
       5. public abstract class User  implements Serializable {  
       6.  .................  
       7.    
       8.  private java.util.List<String> mobiles;  
       9.    
      10.  public java.util.List<String> getMobiles() {  
      11.   return mobiles;  
      12.  }  
      13.  
      14.  public void setmobiles(java.util.List<String> mobiles) {  
      15.   this.mobiles = mobiles;  
      16.  }  
      17.  .................  
      18. }  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值