hibernate 自定义类型映射(转载)

最近做一个很小的系统,其中用到了一个复合主键,本人其实是刚刚开始学习hibernate的,对它的很多的东西都不是很了解。突然发现其实用复合主键是多么的不好。呵呵,个人观点。当然是在发现了hibernate有比它更好的东西是时候才这样说这样想的,这个东西当然就是今天我想说的UserType.故名思义,就是用户自己定义的数据类型。这是一个接口,用户可以实现它以定义出自己的数据类型。下面我们以一个在网 上广为流传的题材为例子给大家讲述一下。就是”用户邮件问题“我是这样叫它的。当我们想为一个用户存多个邮件地址的时候就出现了这个问题。怎么样组织我们的数据库??呵呵,我们这儿为了配合我们的主题当然是要选取一种很特别的组织方式:一个String来存储所有的Email然后在每一个Email之间用一个";"符号分开。很有意思的一种方式,以前可能只有在邮件群发的时候才可能看到吧。先来一点点直观的东西:我的这个示例的整体的文件组织形式图。

下面我们来一步一步的分析 我们的代码:首先当然是要建好我们的数据库的表:这里就叫user

它有三个字段:id int name String email String当然我们对email有特别的要求的。

下面来看看我们的配置文件:hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools. -->
<hibernate-configuration>

<session-factory>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/Hibernate</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">1111</property>
<property name="hibernate.connection.driver_class">org.gjt.mm.mysql.Driver</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<mapping resource="com/terence/usertype/user.hbm.xml"/>
</session-factory>
</hibernate-configuration>

第二个配置文件:user.hbm.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.terence.usertype.User" table="user">
<id name="id" column="id">
<generator class="increment"></generator>
</id>
<property name="name" column="name"></property>
<property name="email" column="email" type="com.terence.usertype.EmailList"></property>
</class>
</hibernate-mapping>

前面这两个文件相对来说比较简单吧!

下面来看一下我们的自定义的数据类型所对谈的类:EmailList.java

package com.terence.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.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;

public class EmailList implements UserType {
//private List emails; //为什么在网上的程序中都加入了这个属性,但好象没有什么用。
private static final char SPLITTER=';';
private static final int[] TYPES=new int[]{Types.VARCHAR};
//用于设定我们的类是不是可变的。
public boolean isMutable()
{
return false;
}
//该自定义对象类型所对应的SQL数据的类型。
public int[] sqlTypes()
{
return TYPES;
}
//用于设定nullSafeGet所返回的数据的类型。即我们的自定义的数据类型。
public Class returnedClass()
{
return List.class;
}
//该方法用于提供自定义类型的完全的复制的方法。它主要用于构造返回对象。
//当nullSafeGet获取对象后,将会调用这个方法。进行复制一个完全相同的拷贝。
//然后把这个拷贝返回给用户。
public Object deepCopy(Object value) throws HibernateException
{
List sourcelist=(List)value;
List targetlist=new ArrayList();
targetlist.addAll(sourcelist);
return targetlist;
}
//这是自定义的数据的对比方法。如果返回的是false则hibernate认为数据发生了变化
//将会把变化更新到库的表之中。
public boolean equals(Object x,Object y)throws HibernateException
{
if(x==y)return true;
if(x!=null&&y!=null)
{
List xList=(List)x;
List yList=(List)y;
if(xList.size()!=yList.size())return false;
for(int i=0;i<xList.size();i++)
{
String strX=(String)xList.get(i);
String strY=(String)yList.get(i);
if(strX!=strY)return false;
}
return true;
}
return false;
}
private String assemble(List emaillist)
{
StringBuffer sb=new StringBuffer();
for(int i=0;i<emaillist.size()-1;i++)
{
sb.append(emaillist.get(i)).append(SPLITTER);
}
sb.append(emaillist.get(emaillist.size()-1));
return sb.toString();
}
private List parse(String email)
{
String[] strs=StringUtils.split(email,String.valueOf(SPLITTER));
List emailList=new ArrayList();
for(int i=0;i<strs.length;i++)
{
emailList.add(strs[i]);
}
return emailList;
}
//这个方法将在数据保存时使用。本方法可以使用PreparedStatement将数据写入对应的数据库字段中。
//其中的value表示的是要写入的值。index表示的是在statement的参数中的index.
public void nullSafeSet(PreparedStatement ps,Object value,int index)
throws HibernateException,SQLException
{
System.out.println("In the set function");
if(value!=null)
{
String str=assemble((List)value);
Hibernate.STRING.nullSafeSet(ps, str,index);
}else
{
Hibernate.STRING.nullSafeSet(ps, value,index);
}
}
//从JDBC的ResultSet中获取到数据,然后返回为相应的类型。
//其中names包含了要映射的字段的名称。
public Object nullSafeGet(ResultSet rs,String[] names,Object owner)
throws HibernateException,SQLException
{
System.out.println("In the get function");
String value=(String)Hibernate.STRING.nullSafeGet(rs, names[0]);
if(value!=null)
{
return parse(value);
}
else
{
return null;
}
}
//下面的方法一般好象没有什么用。可能是还没有用到吧。
public Object assemble(Serializable arg0, Object arg1)
throws HibernateException
{
return null;
}

public Serializable disassemble(Object arg0) throws HibernateException
{
return null;
}

public int hashCode(Object arg0) throws HibernateException
{
return 0;
}

public Object replace(Object arg0, Object arg1, Object arg2)
throws HibernateException
{
return null;
}

}

说明:这个类实现了UserType我们可以使用Eclipse来帮我们生成一部分的代码。其中对每一个有用的方法的用途都进行了比较详细的说明。大家可以仔细一点点的看。

下面我们来看一下我们的VO的代码:User.java

package com.terence.usertype;

import java.util.List;

public class User {
private Integer id;
private String name;
private List email;
public User() {
super();
}
public List getEmail() {
return email;
}
public void setEmail(List email) {
this.email = email;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

最后一步就是来看一下我们的测试的代码:本来想用Junit进行测试的,但为了明白我还是决定用这个让大家都能看明白。Test.java

package com.terence.usertype;
import java.util.List;
import java.util.ListIterator;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class Test {

public static void main(String[] args) throws Exception{
Configuration config = new Configuration().configure();
SessionFactory factory = config.buildSessionFactory();
Session session = factory.openSession();
Query query = session.createQuery("from User as a");

ListIterator iterator = query.list().listIterator();
User tt = (User) iterator.next();
List emails = tt.getEmail();
for (int i = 0; i < emails.size(); i++) {
String emailStr = (String)emails.get(i);
System.out.println(emailStr);
}
session.close();
}

}

下面是我的测试的结果:




log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.

如果看不明白的可以发邮件给我,我们一起探讨。terence zhao

转载:http://hi.baidu.com/lovelink/item/2e201b28b5c8cec3ee10f1a3
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值