转载于: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;
}

.................
}

Hibernate高级映射技术(二)自定义数据类型StringMap (转载用于收藏)相关推荐

  1. Hibernate高级映射技术(二)自定义数据类型StringMap(转)

    核心提示:上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型StringList.这次是我做的另一种自定义数据类型StringMap. 在商品和属性的对应关系中,一个商品对应多个 ...

  2. Hibernate高级映射技术(一)自定义数据类型StringList (转载用于收藏)

    转载于:http://ajava.org/course/open/14003.html 核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免 ...

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

    核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个 ...

  4. hibernate 高级映射 --张国亮总结第一季

    在做持久化类的时候的规定: 1).有一个默认的构造方法: 2).所有的属性都有setter和getter方法 3).有一个对象标识符Oid; 4).如果有集合属性,则必须定义成接口类型:List.Se ...

  5. hibernate的映射之二(一对多双向关联)

    hibernate的一对多双关联 一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多 hihernate一对多关联映射(双向Dept<----->Emp) 一对多双 ...

  6. 480集课程-打通Python开发的任督二脉 轻松掌握Python高级开发技术 Python超级学科课程

    480集课程-打通Python开发的任督二脉 轻松掌握Python高级开发技术 Python超级学科课程 ===============课程目录=============== ├─(1) 01-Pyt ...

  7. RHEL6.3 DNS高级技术二 通过DNS主从区域复制实现DNS View负载均衡和冗余备份

    RHEL6.3 DNS高级技术二 ----通过DNS主从区域复制实现DNS View负载均衡和冗余备份 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 ...

  8. mybatis高级映射多对多查询(二)

    在这篇博客中,我来介绍下mybatis中的多对多查询的案例,在mybatis中,如何使用ResultMap来实现多对多的查询? 案例:一个user可以有很多role,一个role可以有很多entitl ...

  9. 有限元matlab_“ANSYS APDL有限元高级分析技术与二次开发”研修班

        课程背景 APDL参数化设计语言,作为ANSYS Mechanical高级分析技术之一,是ANSYS高级用户不可或缺的应用技术之一.为提高广大学员利用ANSYS软件解决实际工程问题的能力,宏新 ...

最新文章

  1. git ssh key创建和github使用
  2. (转载)深入浅出设计模式——桥接模式(Bridge Pattern)
  3. pycharm打开python文件如何自动创建项目_pycharm 怎么自动创建python头文件?
  4. 在终端显示文本的中间部分
  5. 用户模式 内核模式 linux,linux – “内核模式”和“用户模式”硬件...
  6. ARM TK1 安装kinect驱动
  7. CVPR 2019 | Stereo R-CNN 3D 目标检测
  8. 明天14点直播间见!5位业内大咖带您解锁数据库内核技术与行业应用
  9. 面试题:判断链表是否存在环
  10. 成功在家用ssh远程连上了学校电脑虚拟机当中的ubuntu(代价是虚拟机全部黑屏只能用SSH连接了!)
  11. Configure Javadoc and Source Code for JRE in Eclipse JDT
  12. elasticsearch问题解决之分片副本UNASSIGNED
  13. 译文-Minor GC vs Major GC vs Full GC
  14. j2me解决模拟器乱码
  15. 『神器』如何免费下载百度文库付费资料?
  16. 请问手机有没有简单好用图片去水印app?这4款手机软件可以实现去水印
  17. CentOS下查看本机ip地址方法
  18. 电脑很大,电脑内存很大为什么还是很卡
  19. Java小游戏中加背景音乐--有图有真相
  20. 学术Assignment写作怎么了解文献内容?

热门文章

  1. 高分系列卫星介绍(GF)
  2. php5.1.6下载,phpnow1 PHPnow 简体中文免费版 V1 5 6 下载
  3. 计算机如何识别这是一个键盘,键盘两个键同时按下时计算机如何识别被按下的是哪个键...
  4. 实现一个鼠标自动按键程序
  5. Dev-C++游戏创作之金山打字通(附带音乐)
  6. 基于ijkplayer封装ffmpeg播放器的录屏实现
  7. SpringMVC——快速入门
  8. 洛谷 P1772 [ZJOI2006]物流运输
  9. 骁龙870和天玑1000+哪个好 天玑1000+和骁龙870对比,哪个更强
  10. CSAPP第三章(续)