Hibernate高级映射技术(一)自定义数据类型StringList (转载用于收藏)
转载于:http://ajava.org/course/open/14003.html
核心提示:我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式
我们在设计数据库时往往会遇到例如用户的多个手机号码的一对多问题,如果设计一个T_MOBILE表保存未免太大动干戈而且影响速度,所以如果没有严格的要求,一般情况我们在T_USER表里设计一个mobiles字段,其中的多个手机号码用;分隔。尽管这样不符合数据库范式的设计原则,但在性能和编码复杂度上确实最低的。
这样如果用Hibernate的String类型来映射,就会得到一个长字符串,每次必须按;分隔后才能使用,这样代码就很冗余。
幸好Hibernate有自定义数据类型的支持,只要实现UserType或CompositeUserType接口。不过这两个接口的内容比较复杂,有很多方法需要实现,不能偷懒哦:-)
下面是我对于用;分隔的字段的自定义数据类型的实现。
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.List;
importorg.hibernate.Hibernate;
importorg.hibernate.HibernateException;
importorg.hibernate.usertype.UserType;
/**
*用分隔符分隔的字符串数组.分隔符默认为";"
*@authorwillishz
*/
publicclassStringListimplementsUserType,Serializable{
publicStringList(){
super();
}
publicStringList(charsplitter){
super();
this.splitter=splitter;
}
publicStringList(List<String>attributeList){
super();
this.attributeList=attributeList;
}
privateList<String>attributeList;
/**
*分隔符
*/
privatecharsplitter=SPLITTER;
/**
*分隔符默认为";"
*/
privatestaticfinalcharSPLITTER=';';
privatestaticfinalint[]SQLTYPES=newint[]{Types.VARCHAR};
publicbooleanisMutable(){
returnfalse;
}
publicint[]sqlTypes(){
returnSQLTYPES;
}
publicObjectassemble(Serializableid,Objectobj)throwsHibernateException{
returnnull;
}
/**
*将List类型的数组拼接成字符串
*@paramattributeList
*@return
*@throwsHibernateException
*/
publicObjectassemble(List<String>attributeList)throwsHibernateException{
if(attributeList==null){
returnnull;
}
StringBufferasbl=newStringBuffer();
asbl.append(attributeList.get(0));
for(inti=1;i<attributeList.size();i++){
asbl.append(splitter).append(attributeList.get(i));
}
returnasbl.toString();
}
/**
*自定义类型的完全复制方法,返回一个和原自定义数据相同的新对象
*
*@paramvaluetheobjecttobecloned,whichmaybenull
*@returnObjectacopy
*@seeorg.hibernate.usertype.UserType#deepCopy(java.lang.Object)
*/
publicObjectdeepCopy(Objectvalue)throwsHibernateException{
if(value==null){
returnnull;
}
ArrayListsourceList=(ArrayList)value;
ArrayListtargetList=newArrayList();
List<String>_attributeList=newArrayList<String>();
targetList.addAll(sourceList);
returntargetList;
}
/**
*自定义数据类型的比较方法
*
*@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){
List<String>xList=(List<String>)x;
List<String>yList=(List<String>)y;
if(xList.size()!=yList.size()){
returnfalse;
}
String_x=null;
String_y=null;
for(inti=0;i<xList.size();i++){
_x=xList.get(i);
_y=yList.get(i);
if(!_x.equalsIgnoreCase(_y)){//caseinsensitive
returnfalse;
}
}
returntrue;
}
returnfalse;
}
publicinthashCode(Objectarg0)throwsHibernateException{
returnattributeList.hashCode();
}
/**
*将以分隔符分隔的字符串解析成一个字符串数组
*
*@paramvalue
*@return
*/
publicList<String>parse(Stringvalue){
if(value==null){
returnnull;
}
String[]strs=org.apache.commons.lang.StringUtils.split(value,splitter);
List<String>attributeList=newArrayList<String>();
for(inti=0;i<strs.length;i++){
attributeList.add(strs[i]);
}
returnattributeList;
}
/**
*从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){
returnparse(value);
}
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((List<String>)value),index);
}else{
Hibernate.STRING.nullSafeSet(pst,value,index);
}
}
publicClassreturnedClass(){
returnStringList.class;
}
publicObjectreplace(Objectarg0,Objectarg1,Objectarg2)throwsHibernateException{
returnnull;
}
publicSerializabledisassemble(Objectarg0)throwsHibernateException{
returnnull;
}
}
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="User"
table="t_user"
>
.................
<property
name="mobiles"
column="mobiles"
type="com.willishz.framework.dao.usertype.StringList"
not-null="false"
length="100"
/>
.................
</class>
</hibernate-mapping>
Hibernate映射实体文件的相关内容:
packagecom.willishz.apocalypse.ebid.domain.base;
importjava.io.Serializable;
publicabstractclassUserimplementsSerializable{
.................
privatejava.util.List<String>mobiles;
publicjava.util.List<String>getMobiles(){
returnmobiles;
}
publicvoidsetmobiles(java.util.List<String>mobiles){
this.mobiles=mobiles;
}
.................
}