您的位置:首页 > 其它

更方便的数据模式: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}的字符串数组的自定义数据类型的实现。

]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;
}

.................
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: