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

核心提示:上一篇文章介绍了数据库中用;分隔的字段的一种方便的高级映射自定义数据类型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}的字符串数组的自定义数据类型的实现。

1. package com.willishz.framework.dao.usertype;
2.
3. import java.io.Serializable;
4. import java.sql.PreparedStatement;
5. import java.sql.ResultSet;
6. import java.sql.SQLException;
7. import java.sql.Types;
8. import java.util.ArrayList;
9. import java.util.Collections;
10. import java.util.HashMap;
11. import java.util.Iterator;
12. import java.util.List;
13. import java.util.Map;
14.
15. import org.apache.commons.collections.map.LinkedMap;
16. import org.hibernate.Hibernate;
17. import org.hibernate.HibernateException;
18. import org.hibernate.usertype.UserType;
19.
20. /**
21. * 格式为{key:value};{key:value1,value2}的字符串数组.
22. * @author willishz
23. */
24. public class StringMap implements UserType, Serializable {
25.
26. public StringMap() {
27. super();
28. }
29.
30. public StringMap(Map attributeMap) {
31. super();
32. this.attributeMap = attributeMap;
33. }
34.
35. private Map attributeMap;
36.
37. public static final String SPLITTER = ";";
38.
39. public static final String SEPARATOR = ":";
40.
41. public static final String VALUE_BREAK = ",";
42.
43. public static final char BRACKET_LEFT = '{';
44.
45. public static final char BRACKET_RIGHT = '}';
46.
47. public static final int[] SQLTYPES = new int[] { Types.VARCHAR };
48.
49. public boolean isMutable() {
50. return false;
51. }
52.
53. public int[] sqlTypes() {
54. return SQLTYPES;
55. }
56.
57. public Object assemble(Serializable id, Object obj) throws HibernateException {
58. return null;
59. }
60.
61. /**
62. * 将Map类型的属性拼接成字符串
63. * @param attributeList
64. * @return
65. * @throws HibernateException
66. */
67. public Object assemble(Map attributeMap) throws HibernateException {
68. if (attributeMap == null) {
69. return null;
70. }
71. StringBuffer asbl = new StringBuffer();
72. Iterator itr = attributeMap.keySet().iterator();
73. String _key = null;
74. while (itr.hasNext()) {
75. _key = (String) itr.next();
76. asbl.append(SPLITTER).append(BRACKET_LEFT).append(_key).append(SEPARATOR).append(attributeMap.get(_key)).append(BRACKET_RIGHT);
77. }
78. return asbl.toString().replaceFirst(SPLITTER, "");
79. }
80.
81. /**
82. * 自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象
83. *
84. * @param value the object to be cloned, which may be null
85. * @return Object a copy
86. * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
87. */
88. public Object deepCopy(Object value) throws HibernateException {
89. if (value == null) {
90. return null;
91. }
92. Map sourceMap = (Map) value;
93. Map targetMap = new HashMap();
94. targetMap.putAll(sourceMap);
95. return targetMap;
96. }
97.
98. /**
99. * 自定义数据类型的比较方法
100. *
101. * @param x
102. * @param y
103. * @return boolean
104. * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
105. */
106. public boolean equals(Object x, Object y) throws HibernateException {
107. if (x == y) {
108. return true;
109. }
110. if (x != null && y != null) {
111. Map xMap = (Map) x;
112. Map yMap = (Map) y;
113. if (xMap.size() != yMap.size()) {
114. return false;
115. }
116. List<String> _xList = new ArrayList(xMap.keySet());
117. List<String> _yList = new ArrayList(xMap.keySet());
118. Collections.sort(_xList);
119. Collections.sort(_yList);
120. for (int i = 0; i < xMap.size(); i++) {
121. if (!_xList.get(i).equals(_yList.get(i))) {
122. return false;
123. }
124. if (!xMap.get(_xList.get(i)).equals(yMap.get(_yList.get(i)))) {
125. return false;
126. }
127. }
128. return true;
129. }
130. return false;
131. }
132.
133. public int hashCode(Object arg0) throws HibernateException {
134. return attributeMap.hashCode();
135. }
136.
137. /**
138. * 将以格式为{key:value};{key:value1,value2}的字符串数组解析成一个Map
139. *
140. * @param value
141. * @return
142. */
143. public Map parse(String value) {
144. if (value == null) {
145. return null;
146. }
147. String[] strs = org.apache.commons.lang.StringUtils.split(value.trim(), SPLITTER);
148. Map attributeMap = new LinkedMap();
149. String _temp = null;
150. for (int i = 0; i < strs.length; i++) {
151. _temp = strs[i].substring(1, strs[i].length() - 1);
152. attributeMap.put(_temp.split(SEPARATOR, 2)[0], _temp.split(SEPARATOR, 2)[1]);
153. }
154. return attributeMap;
155. }
156.
157. /**
158. * 从JDBC的ResultSet中读取数据,并将其转换为自定义类型后返回。
159. * 此方法要求对可能出现null的情况做处理。
160. * names中包含了当前自定义类型的映射字段名称。
161. *
162. * @param rs a JDBC result set
163. * @param names the column names
164. * @param owner the containing entity
165. * @return Object
166. * @throws HibernateException
167. * @throws SQLException
168. * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
169. */
170. public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
171. throws HibernateException, SQLException {
172. String value = (String) Hibernate.STRING.nullSafeGet(rs, names[0]);
173. if (value != null) {
174. attributeMap = parse(value);
175. return attributeMap;
176. }
177. return null;
178. }
179.
180. /**
181. * 在Hibernate进行数据保存时被调用
182. * 可以通过PreparedStatement将自定义数据写入对应的数据库字段中
183. * names中包含了当前自定义类型的映射字段名称。
184. *
185. * @param st a JDBC prepared statement
186. * @param value the object to write
187. * @param index statement parameter index
188. * @throws HibernateException
189. * @throws SQLException
190. * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
191. */
192. public void nullSafeSet(PreparedStatement pst, Object value, int index)
193. throws HibernateException, SQLException {
194. if (value != null) {
195. Hibernate.STRING.nullSafeSet(pst, assemble((Map) value), index);
196. } else {
197. Hibernate.STRING.nullSafeSet(pst, value, index);
198. }
199. }
200.
201. public Class returnedClass() {
202. return StringMap.class;
203. }
204.
205. public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {
206. return null;
207. }
208.
209. public Serializable disassemble(Object arg0) throws HibernateException {
210. return null;
211. }
212.
213. public Map getAttributeMap() {
214. return attributeMap;
215. }
216.
217. public void setAttributeMap(Map attributeMap) {
218. this.attributeMap = attributeMap;
219. }
220. }
221.
222.

Hibernate配置文件的相关内容如下:

1. <?xml version="1.0"?>
2. <!DOCTYPE hibernate-mapping PUBLIC
3. "-//Hibernate/Hibernate Mapping DTD//EN"
4. "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
5.
6. <hibernate-mapping package="com.willishz.apocalypse.ebid.domain">
7. <class
8. name="Merchandise"
9. table="t_merchandise"
10. lazy="false"
11. >
12. .................
13. <property
14. name="specification"
15. column="specification"
16. type="com.willishz.framework.dao.usertype.StringMap"
17. not-null="false"
18. />
19. .................
20. </class>
21. </hibernate-mapping>

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

1. package com.willishz.apocalypse.ebid.domain.base;
2.
3. import java.io.Serializable;
4.
5. public abstract class User implements Serializable {
6. .................
7.
8. private java.util.Map specification;
9.
10. /**
11. * Return the value associated with the column: specification
12. */
13. public java.util.Map getSpecification () {
14. return specification;
15. }
16.
17. /**
18. * Set the value related to the column: specification
19. * @param specification the specification value
20. */
21. public void setSpecification (java.util.Map specification) {
22. this.specification = specification;
23. }
24.
25. .................
26. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值