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}的字符串数组的自定义数据类型的实现。
packagecom.willishz.framework.dao.usertype;
importjava.io.Serializable;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.sql.Types;
importjava.util.ArrayList;
importjava.util.Collections;
importjava.util.HashMap;
importjava.util.Iterator;
importjava.util.List;
importjava.util.Map;
importorg.apache.commons.collections.map.LinkedMap;
importorg.hibernate.Hibernate;
importorg.hibernate.HibernateException;
importorg.hibernate.usertype.UserType;
/**
*格式为{key:value};{key:value1,value2}的字符串数组.
*@authorwillishz
*/
publicclassStringMapimplementsUserType,Serializable{
publicStringMap(){
super();
}
publicStringMap(MapattributeMap){
super();
this.attributeMap=attributeMap;
}
privateMapattributeMap;
publicstaticfinalStringSPLITTER=";";
publicstaticfinalStringSEPARATOR=":";
publicstaticfinalStringVALUE_BREAK=",";
publicstaticfinalcharBRACKET_LEFT='{';
publicstaticfinalcharBRACKET_RIGHT='}';
publicstaticfinalint[]SQLTYPES=newint[]{Types.VARCHAR};
publicbooleanisMutable(){
returnfalse;
}
publicint[]sqlTypes(){
returnSQLTYPES;
}
publicObjectassemble(Serializableid,Objectobj)throwsHibernateException{
returnnull;
}
/**
*将Map类型的属性拼接成字符串
*@paramattributeList
*@return
*@throwsHibernateException
*/
publicObjectassemble(MapattributeMap)throwsHibernateException{
if(attributeMap==null){
returnnull;
}
StringBufferasbl=newStringBuffer();
Iteratoritr=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);
}
returnasbl.toString().replaceFirst(SPLITTER,"");
}
/**
*自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象
*
*@paramvaluetheobjecttobecloned,whichmaybenull
*@returnObjectacopy
*@seeorg.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/
publicObjectdeepCopy(Objectvalue)throwsHibernateException{
if(value==null){
returnnull;
}
MapsourceMap=(Map)value;
MaptargetMap=newHashMap();
targetMap.putAll(sourceMap);
returntargetMap;
}
/**
*自定义数据类型的比较方法
*
*@paramx
*@paramy
*@returnboolean
*@seeorg.hibernate.usertype.UserType#equals(java.lang.Object,java.lang.Object)
*/
publicbooleanequals(Objectx,Objecty)throwsHibernateException{
if(x==y){
returntrue;
}
if(x!=null&&y!=null){
MapxMap=(Map)x;
MapyMap=(Map)y;
if(xMap.size()!=yMap.size()){
returnfalse;
}
List<String>_xList=newArrayList(xMap.keySet());
List<String>_yList=newArrayList(xMap.keySet());
Collections.sort(_xList);
Collections.sort(_yList);
for(inti=0;i<xMap.size();i++){
if(!_xList.get(i).equals(_yList.get(i))){
returnfalse;
}
if(!xMap.get(_xList.get(i)).equals(yMap.get(_yList.get(i)))){
returnfalse;
}
}
returntrue;
}
returnfalse;
}
publicinthashCode(Objectarg0)throwsHibernateException{
returnattributeMap.hashCode();
}
/**
*将以格式为{key:value};{key:value1,value2}的字符串数组解析成一个Map
*
*@paramvalue
*@return
*/
publicMapparse(Stringvalue){
if(value==null){
returnnull;
}
String[]strs=org.apache.commons.lang.StringUtils.split(value.trim(),SPLITTER);
MapattributeMap=newLinkedMap();
String_temp=null;
for(inti=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]);
}
returnattributeMap;
}
/**
*从JDBC的ResultSet中读取数据,并将其转换为自定义类型后返回。
*此方法要求对可能出现null的情况做处理。
*names中包含了当前自定义类型的映射字段名称。
*
*@paramrsaJDBCresultset
*@paramnamesthecolumnnames
*@paramownerthecontainingentity
*@returnObject
*@throwsHibernateException
*@throwsSQLException
*@seeorg.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,java.lang.String[],java.lang.Object)
*/
publicObjectnullSafeGet(ResultSetrs,String[]names,Objectowner)
throwsHibernateException,SQLException{
Stringvalue=(String)Hibernate.STRING.nullSafeGet(rs,names[0]);
if(value!=null){
attributeMap=parse(value);
returnattributeMap;
}
returnnull;
}
/**
*在Hibernate进行数据保存时被调用
*可以通过PreparedStatement将自定义数据写入对应的数据库字段中
*names中包含了当前自定义类型的映射字段名称。
*
*@paramstaJDBCpreparedstatement
*@paramvaluetheobjecttowrite
*@paramindexstatementparameterindex
*@throwsHibernateException
*@throwsSQLException
*@seeorg.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,java.lang.String[],java.lang.Object)
*/
publicvoidnullSafeSet(PreparedStatementpst,Objectvalue,intindex)
throwsHibernateException,SQLException{
if(value!=null){
Hibernate.STRING.nullSafeSet(pst,assemble((Map)value),index);
}else{
Hibernate.STRING.nullSafeSet(pst,value,index);
}
}
publicClassreturnedClass(){
returnStringMap.class;
}
publicObjectreplace(Objectarg0,Objectarg1,Objectarg2)throwsHibernateException{
returnnull;
}
publicSerializabledisassemble(Objectarg0)throwsHibernateException{
returnnull;
}
publicMapgetAttributeMap(){
returnattributeMap;
}
publicvoidsetAttributeMap(MapattributeMap){
this.attributeMap=attributeMap;
}
}
Hibernate配置文件的相关内容如下:
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mappingPUBLIC
"-//Hibernate/HibernateMappingDTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mappingpackage="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映射实体文件的相关内容:
packagecom.willishz.apocalypse.ebid.domain.base;
importjava.io.Serializable;
publicabstractclassUserimplementsSerializable{
.................
privatejava.util.Mapspecification;
/**
*Returnthevalueassociatedwiththecolumn:specification
*/
publicjava.util.MapgetSpecification(){
returnspecification;
}
/**
*Setthevaluerelatedtothecolumn:specification
*@paramspecificationthespecificationvalue
*/
publicvoidsetSpecification(java.util.Mapspecification){
this.specification=specification;
}
.................
}