Hibernate高级映射技术(二)自定义数据类型StringMap (用于收藏)

转载于:http://ajava.org/course/open/14004.html
    核心提示:上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型StringList。这次是我做的另一种自定义数据类型StringMap。 在商品和属性的对应关系中,一个商品对应多个属性,例如一个数码相机型号对应有:像素:1000万,焦距:35-200mm,感光度

    上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型StringList。这次是我做的另一种自定义数据类型StringMap。

    在商品和属性的对应关系中,一个商品对应多个属性,例如一个数码相机型号对应有:像素:1000万,焦距:35-200mm,感光度:ISO100-1600,非常多而且还需要能适应随时增加新的属性,快速读取显示特别是可以检索。如果设计一个Attribute表(主键attriId,attrKey,attrValue,商品表的外键itemId)的一对多,不仅读取显示很慢,而且难以维护,特别是很难做检索,想搜ISO1600并且焦距200mm的1000万像素的相机,SQL就非常繁琐。所以一般使用将这些属性统一放到商品表的一个specification字段里,结构自已定义,我设置的结构是{key:value};{key:value1,value2}的字符串数组。这样再做刚才的检索时只要在一个表的一个字段里查询,就非常简单了!

    幸好Hibernate有自定义数据类型的支持,只要实现UserType或CompositeUserType接口。不过这两个接口的内容比较复杂,有很多方法需要实现,不能偷懒哦:-)
下面是我对于用{key:value};{key:value1,value2}的字符串数组的自定义数据类型的实现。

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.Collections;   
import java.util.HashMap;   
import java.util.Iterator;   
import java.util.List;   
import java.util.Map;   
  
import org.apache.commons.collections.map.LinkedMap;   
import org.hibernate.Hibernate;   
import org.hibernate.HibernateException;   
import org.hibernate.usertype.UserType;   
  
/**  
* 格式为{key:value};{key:value1,value2}的字符串数组.  
* @author willishz  
*/  
public class StringMap implements UserType, Serializable {   
  
public StringMap() {   
  super();   
}   
  
public StringMap(Map attributeMap) {   
  super();   
  this.attributeMap = attributeMap;   
}   
  
private Map attributeMap;   
  
public static final String SPLITTER = ";";   
  
public static final String SEPARATOR = ":";   
  
public static final String VALUE_BREAK = ",";   
  
public static final char BRACKET_LEFT = '{';   
  
public static final char BRACKET_RIGHT = '}';   
  
public 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;   
}   
  
/**  
  * 将Map类型的属性拼接成字符串  
  * @param attributeList  
  * @return  
  * @throws HibernateException  
  */  
public Object assemble(Map attributeMap) throws HibernateException {   
  if (attributeMap == null) {   
   return null;   
  }   
  StringBuffer asbl = new StringBuffer();   
  Iterator itr = attributeMap.keySet().iterator();   
  String _key = null;   
  while (itr.hasNext()) {   
   _key = (String) itr.next();   
   asbl.append(SPLITTER).append(BRACKET_LEFT).append(_key).append(SEPARATOR).append(attributeMap.get(_key)).append(BRACKET_RIGHT);   
  }   
  return asbl.toString().replaceFirst(SPLITTER, "");   
}   
  
/**  
  * 自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象  
  *  
  * @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;   
  }   
  Map sourceMap = (Map) value;   
  Map targetMap = new HashMap();   
  targetMap.putAll(sourceMap);   
  return targetMap;   
}   
  
/**  
  * 自定义数据类型的比较方法  
  *   
  * @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) {   
   Map xMap = (Map) x;   
   Map yMap = (Map) y;   
   if (xMap.size() != yMap.size()) {   
    return false;   
   }   
   List<String> _xList = new ArrayList(xMap.keySet());   
   List<String> _yList = new ArrayList(xMap.keySet());   
   Collections.sort(_xList);   
   Collections.sort(_yList);   
   for (int i = 0; i < xMap.size(); i++) {   
    if (!_xList.get(i).equals(_yList.get(i))) {   
     return false;   
    }   
    if (!xMap.get(_xList.get(i)).equals(yMap.get(_yList.get(i)))) {   
     return false;   
    }   
   }   
   return true;   
  }   
  return false;   
}   
  
public int hashCode(Object arg0) throws HibernateException {   
  return attributeMap.hashCode();   
}   
  
/**  
  * 将以格式为{key:value};{key:value1,value2}的字符串数组解析成一个Map  
  *   
  * @param value  
  * @return  
  */  
public Map parse(String value) {   
  if (value == null) {   
   return null;   
  }   
  String[] strs = org.apache.commons.lang.StringUtils.split(value.trim(), SPLITTER);   
  Map attributeMap = new LinkedMap();   
  String _temp = null;   
  for (int i = 0; i < strs.length; i++) {   
   _temp = strs[i].substring(1, strs[i].length() - 1);   
   attributeMap.put(_temp.split(SEPARATOR, 2)[0], _temp.split(SEPARATOR, 2)[1]);   
  }   
  return attributeMap;   
}   
  
/**  
  * 从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) {   
   attributeMap = parse(value);   
   return attributeMap;   
  }   
  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((Map) value), index);   
  } else {   
   Hibernate.STRING.nullSafeSet(pst, value, index);   
  }   
}   
  
public Class returnedClass() {   
  return StringMap.class;   
}   
  
public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {   
  return null;   
}   
  
public Serializable disassemble(Object arg0) throws HibernateException {   
  return null;   
}   
  
public Map getAttributeMap() {   
  return attributeMap;   
}   
  
public void setAttributeMap(Map attributeMap) {   
  this.attributeMap = attributeMap;   
}   
}   
  
   

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="Merchandise"  
  table="t_merchandise"  
  lazy="false"  
>  
.................   
  <property  
   name="specification"  
   column="specification"  
   type="com.willishz.framework.dao.usertype.StringMap"  
   not-null="false"  
  />  
.................   
</class>    
</hibernate-mapping>  

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

package com.willishz.apocalypse.ebid.domain.base;   
  
import java.io.Serializable;   
  
public abstract class User  implements Serializable {   
.................   
    
private java.util.Map specification;   
  
/**  
  * Return the value associated with the column: specification  
  */  
public java.util.Map getSpecification () {   
  return specification;   
}   
  
/**  
  * Set the value related to the column: specification  
  * @param specification the specification value  
  */  
public void setSpecification (java.util.Map specification) {   
  this.specification = specification;   
}   
  
.................   
}  

你可能感兴趣的:(java,数据结构,sql,Hibernate,jdbc)