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

你可能感兴趣的:(Hibernate)