更方便的数据模式:Hibernate高级映射技术——自定义数据类型StringMap
2009-08-19 13:45
525 查看
上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型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}的字符串数组的自定义数据类型的实现。
Hibernate配置文件的相关内容如下:
Hibernate映射实体文件的相关内容:
在商品和属性的对应关系中,一个商品对应多个属性,例如一个数码相机型号对应有:像素: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; } ................. }
相关文章推荐
- 更方便的数据模式:Hibernate高级映射技术——自定义数据类型StringList
- Hibernate映射自定义数据类型
- Hibernate自定义数据类型映射
- Hibernate自定义数据类型映射oracle中xmlType 广东精鹰软件工作室(刘正仁)
- 使用Hibernate的XML配置来映射枚举类型,存储自定义类型数据
- JavaBean之间拷贝利器-Dozer 映射数据类型不一致,级联映射与自定义映射
- hibernate数据类型映射表
- Hibernate 映射 数据类型
- Hibernate使用自定义类型UserType映射Oracle的Date类型
- 自定义数据类型的数据库映射方案
- 自定义数据类型映射
- Hibernate的基本映射数据类型----(1)
- Hibernate中几种数据类型的映射
- Hibernate的自定义数据类型实现接口——UserType详解
- 终结守卫者模式在HashMap关系数据映射技术软件PVO中的应用
- Hibernate映射文件——数据类型转换
- hibernate中java类的成员变量类型如何映射到SQL中的数据类型变化
- 自定义数据类型的数据库映射方案
- Hibernate数据类型映射关系
- hibernate-mysql数据类型映射