`
aflyer
  • 浏览: 36727 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

使用Hibernate的客户化映射类型

阅读更多

Hibernate提供客户化映射类型接口,使用户能以编程方式创建自定义的映射类型来将持久化类任意类型的属性映射到数据库中。使用客户化映射类型,需要实现org.hibernate.usertype.UserType接口。这是个强大的功能,也是Hibernate的最佳实践之一。我们经常提到ORM中很困难的一点便是O的属性和R的属性不能一一映射,而Hibernate提供的UserType无疑给出了一个很好的解决方案。本文给出使用客户化映射类型的两个例子,算是对Hibernate初学者的抛砖。
    第一个例子是使用UserType映射枚举类型。假设Account表中含有一sex列,类型为tinyint(当前其0代表男,1代表女,将来可能出现2等代表其他性别类型);我们当然可以在对应的Account类中添加int类型的sex属性,但这种数字化无显示意义且类型不安全的枚举不是很好的解决方式,这里就采用了java5的enum来作为Account类的性别属性(如果不熟悉java5的enum,也可采用《effective java》中提到的经典的类型安全的枚举方案)。在Account添加enum Gender:

java 代码
  1. public class Account extends AbstractDomain<Long>{   
  2.        
  3.     public enum Gender{   
  4.         Male("male",0),   
  5.         Female("female",1);   
  6.            
  7.         private String name;   
  8.         private int value;   
  9.            
  10.         public String getName() {   
  11.             return name;   
  12.         }   
  13.         public int getValue() {   
  14.             return value;   
  15.         }   
  16.            
  17.         private Gender(String name,int value){   
  18.             this.name = name;   
  19.             this.value = value;   
  20.         }   
  21.            
  22.         public static Gender getGender(int value){   
  23.             if(0 == value)return Male;   
  24.             else if(1 == value)return Female;   
  25.             else throw new RuntimeException();   
  26.         }   
  27.            
  28.     }   
  29.        
  30.     private Gender gender;   
  31.     public Gender getGender() {   
  32.         return gender;   
  33.     }   
  34.     public void setGender(Gender gender) {   
  35.         this.gender = gender;   
  36.     }   
  37.        //省略其他       
  38. }  
接下来定义实现UserType接口的GenderUserType:
java 代码
  1. public class GenderUserType implements UserType{   
  2.   
  3.     public Object assemble(Serializable arg0, Object arg1) throws HibernateException {   
  4.         return null;   
  5.     }   
  6.   
  7.     /*  
  8.      *  这是用于Hibernate缓存生成的快照,由于Gender是不可变的,直接返回就好了。  
  9.      */  
  10.     public Object deepCopy(Object arg0) throws HibernateException {   
  11.         return arg0;   
  12.     }   
  13.   
  14.     public Serializable disassemble(Object arg0) throws HibernateException {   
  15.         return null;   
  16.     }   
  17.   
  18.     /*  
  19.      * 由于Gender是不可变的,因此直接==了,这个方法将在insert、update时用到。  
  20.      */  
  21.     public boolean equals(Object x, Object y) throws HibernateException {   
  22.         return x == y;   
  23.     }   
  24.   
  25.     public int hashCode(Object o) throws HibernateException {   
  26.         return o.hashCode();   
  27.     }   
  28.   
  29.     /*  
  30.      * 表明Gender是不是可变类(很重要的概念哦),这里的Gender由于是枚举所以是不可变的  
  31.      */  
  32.     public boolean isMutable() {   
  33.         return false;   
  34.     }   
  35.   
  36.     /*  
  37.      *  从ResultSet读取sex并返回Gender实例,这个方法是在从数据库查询数据时用到。  
  38.      */  
  39.     public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {   
  40.         int value = rs.getInt(names[0]);   
  41.         return Account.Gender.getGender(value);   
  42.     }   
  43.   
  44.     /*  
  45.      *  将Gender的value设置到PreparedStatement。  
  46.      */  
  47.     public void nullSafeSet(PreparedStatement ps, Object value, int index) throws HibernateException, SQLException {   
  48.         if(value == null){   
  49.             ps.setInt(index,Account.Gender.Male.getValue());   
  50.         }else{   
  51.             ps.setInt(index,((Account.Gender)value).getValue());   
  52.         }   
  53.     }   
  54.   
  55.     public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {   
  56.         return null;   
  57.     }   
  58.   
  59.     /*  
  60.      * 设置映射的Gender类  
  61.      */  
  62.     public Class returnedClass() {   
  63.         return Account.Gender.class;   
  64.     }   
  65.   
  66.     /*  
  67.      *  设置Gender枚举中的value属性对应的Account表中的sex列的SQL类型  
  68.      */  
  69.     public int[] sqlTypes() {   
  70.         int[] typeList = {Types.TINYINT};   
  71.         return typeList;   
  72.     }   
  73. }  
 最后在Account的配置文件中配置gender属性就好了:
<property name="gender" type="org.prague.domain.util.GenderUserType" column="sex"></property>
    除了可以使用 UserType映射枚举类型,也可以使用Hibernate的PersistentEnum来实现同样的功能,感兴趣的朋友可以参考文章http://www.hibernate.org/203.html。

    
    第二个例子是关于email的。假设Account表中email是一个varchar型的字段,而Account中的Email是如下的类:
java 代码
  1. public class Email {   
  2.     String username;   
  3.   
  4.     String domain;   
  5.   
  6.     public Email() {   
  7.     }   
  8.   
  9.     public Email(String username, String domain) {   
  10.         this.username = username;   
  11.         this.domain = domain;   
  12.     }   
  13.   
  14.     public String getUsername() {   
  15.         return username;   
  16.     }   
  17.   
  18.     public String getDomain() {   
  19.         return domain;   
  20.     }   
  21.   
  22.        
  23.     public void setDomain(String domain) {   
  24.         this.domain = domain;   
  25.     }   
  26.   
  27.     public void setUsername(String username) {   
  28.         this.username = username;   
  29.     }   
  30.   
  31.     public String toString() {   
  32.         return username + '@' + domain;   
  33.     }   
  34.   
  35.     public static Email parse(String email) {   
  36.         Email e = new Email();   
  37.         int at = email.indexOf('@');   
  38.         if (at == -1) {   
  39.             throw new IllegalArgumentException("Invalid email address");   
  40.         }   
  41.   
  42.         e.username = email.substring(0, at);   
  43.         e.domain = email.substring(at + 1);   
  44.   
  45.         return e;   
  46.     }   
  47.   
  48.     @Override  
  49.     public int hashCode() {   
  50.         final int PRIME = 31;   
  51.         int result = 1;   
  52.         result = PRIME * result + ((domain == null) ? 0 : domain.hashCode());   
  53.         result = PRIME * result + ((username == null) ? 0 : username.hashCode());   
  54.         return result;   
  55.     }   
  56.   
  57.     @Override  
  58.     public boolean equals(Object obj) {   
  59.         if (this == obj)    return true;   
  60.       if(null == obj)return false;   
  61.         if (getClass() != obj.getClass())   
  62.             return false;   
  63.         final Email other = (Email) obj;   
  64.         if (domain == null) {   
  65.             if (other.domain != null)   
  66.                 return false;   
  67.         } else if (!domain.equals(other.domain))   
  68.             return false;   
  69.         if (username == null) {   
  70.             if (other.username != null)   
  71.                 return false;   
  72.         } else if (!username.equals(other.username))   
  73.             return false;   
  74.         return true;   
  75.     }   
  76. }   
  77.     email是Account类的一个属性:   
  78. public class Account extends AbstractDomain<Long>{   
  79.        
  80.     private Email email;   
  81.     public Email getEmail() {   
  82.         return email;   
  83.     }   
  84.     public void setEmail(Email email) {   
  85.         this.email = email;   
  86.     }   
  87.   
  88.     //省略其他       
  89. }  
这样的情况下,需要将email的username + '@' + domain映射到Account表的email列,定义一个EmailUserType如下:
java 代码
  1. public class EmailUserType implements UserType{   
  2.   
  3.     public Object assemble(Serializable arg0, Object arg1) throws HibernateException {   
  4.         return null;   
  5.     }   
  6.   
  7.     public Object deepCopy(Object o) throws HibernateException {   
  8.         if(null == o)return null;   
  9.         Email e = (Email)o;   
  10.         return new Email(e.getUsername(),e.getDomain());   
  11.     }   
  12.   
  13.     public Serializable disassemble(Object arg0) throws HibernateException {   
  14.         return null;   
  15.     }   
  16.   
  17.     public boolean equals(Object x, Object y) throws HibernateException {   
  18.         if(x == y)return true;   
  19.         if(x == null || y == null)return false;   
  20.         boolean  f = x.equals(y);   
  21.         return f;   
  22.     }   
  23.   
  24.     public int hashCode(Object o) throws HibernateException {   
  25.         return o.hashCode();   
  26.     }   
  27.   
  28.     public boolean isMutable() {   
  29.         return true;   
  30.     }   
  31.   
  32.     public Object nullSafeGet(ResultSet rs, String[] names, Object o) throws HibernateException, SQLException {   
  33.         String email = rs.getString(names[0]);   
  34.         if(email == null)return null;   
  35.         int index = email.indexOf("@");   
  36.         if(index < 0)throw new RuntimeException();   
  37.         return new Email(email.substring(0,index),email.substring(index+1));   
  38.     }   
  39.   
  40.     public void nullSafeSet(PreparedStatement ps, Object o, int index) throws HibernateException, SQLException {   
  41.         if(o == null )ps.setNull(index, Types.VARCHAR);   
  42.         else{   
  43.             Email e = (Email)o;   
  44.             if(e.getDomain() == null || e.getUsername() == null)ps.setNull(index, Types.VARCHAR);   
  45.             else{   
  46.                 String email = e.getUsername() + "@" + e.getDomain();   
  47.                 ps.setString(index, email);   
  48.             }   
  49.         }   
  50.            
  51.     }   
  52.   
  53.     public Object replace(Object arg0, Object arg1, Object arg2) throws HibernateException {   
  54.         return null;   
  55.     }   
  56.   
  57.     public Class returnedClass() {   
  58.         return Email.class;   
  59.     }   
  60.   
  61.     public int[] sqlTypes() {   
  62.         int[] typeList = {Types.VARCHAR};   
  63.         return typeList;   
  64.     }   
  65. }  
最后配置下 email 属性:
<property name="email" type="org.prague.domain.util.EmailUserType" column="email"></property>
    相比于Gedner,Email是一个可变类(如果想将其变为不可变类,只需要去掉属性的set方法),因此EmailUserType中的equals要用到Email的equals(hashCode())方法,而deepCopy(Object o) 要做到是深拷贝,否则即便Email属性内容改变,由于Hibernate缓存中的快照指向的对象不变,在update时可能不起作用(在指定了dynamic-update属性的清况下)。
分享到:
评论

相关推荐

    hibernate 无主键表映射

    在Java的持久化框架Hibernate中,无主键表映射是一种特殊情况,主要处理那些在数据库中没有明确单一主键的表。这种情况通常出现在那些通过多个字段共同唯一标识一条记录的复合主键(Composite Key)场景。本文将详细...

    Hibernate3.x关联映射示例

    Hibernate 3.x 版本是其成熟且广泛使用的版本,提供了丰富的功能和优化,包括对象的持久化、查询语言HQL以及关联映射。本示例将深入探讨 Hibernate 3.x 中的关联映射,以帮助开发者更好地理解和应用这一关键技术。 ...

    JAVA培训-HIBERNATE的集合映射.doc

    在给定的文档“JAVA培训-HIBERNATE的集合映射.doc”中,主要讲解了Hibernate如何处理不同类型的集合映射,包括Set、List、Array、Map和Bag。我们将详细讨论这些集合映射以及它们在实际应用中的使用。 首先,我们来...

    Hibernate 中的映射关系

    在Java的持久化框架Hibernate中,映射关系是核心概念之一,它负责将数据库的表结构与Java对象之间建立关联,使得数据操作更加便捷。以下是对每个映射关系的详细解释: 1. 一对多(One-to-Many):这种关系意味着一...

    hibernate 全面学习->hibernate 关联映射学习

    使用Hibernate进行关联映射时,需要考虑性能因素,比如懒加载和急加载策略,以及级联操作等。此外,合理设计数据库表结构和实体模型,可以有效避免N+1查询问题,提高系统效率。 总之,Hibernate的关联映射是其核心...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part2

     11.2.1 用客户化映射类型取代Hibernate组件  11.2.2 用UserType映射枚举类型  11.2.3 实现CompositeUserType接口  11.2.4 运行本节范例程序  11.3 操纵Blob和Clob类型数据  11.4 小结  11.5 思考题 第12章 ...

    hibernate 一对多多对一的映射

    在Java持久化领域,Hibernate是一个非常重要的框架,它简化了对象关系映射(ORM)的过程,使得Java开发者能够更方便地操作数据库。本教程将详细讲解如何使用Hibernate来实现MySQL数据库中的一对多和多对一的映射关系...

    hibernate各种映射的配置

    在Java持久化框架Hibernate中,映射配置是连接数据库对象模型和Java对象模型的关键。本文将详细介绍四种常见的Hibernate映射关系:一对一、唯一外键一对一、简单多对一单向关联以及一对多双向关联。 1. 一对一映射...

    精通hibernate:对象持久化技术孙卫琴第二版part2

    2.4.3 Hibernate映射类型接口 41 2.4.4 可供扩展的接口 42 2.5 小结 43 2.6 思考题 45 第3章 第一个Hibernate应用 47 本章通过简单的helloapp应用例子,演示如何利用Hibernate来持久化Java对象。 3.1 创建...

    JSP+Struts+Hibernate办公自动化管理系统

    Hibernate是一个优秀的对象关系映射(ORM)工具,它允许开发者使用面向对象的方式来操作数据库,降低了SQL和数据库管理的复杂性。在本系统中,Hibernate负责数据库的操作,如查询、插入、更新和删除数据。通过...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part4

     11.2.1 用客户化映射类型取代Hibernate组件  11.2.2 用UserType映射枚举类型  11.2.3 实现CompositeUserType接口  11.2.4 运行本节范例程序  11.3 操纵Blob和Clob类型数据  11.4 小结  11.5 思考题 第12章 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part3

     11.2.1 用客户化映射类型取代Hibernate组件  11.2.2 用UserType映射枚举类型  11.2.3 实现CompositeUserType接口  11.2.4 运行本节范例程序  11.3 操纵Blob和Clob类型数据  11.4 小结  11.5 思考题 第12章 ...

    精通 Hibernate:Java 对象持久化技术详解(第2版).part1.rar

     11.2.1 用客户化映射类型取代Hibernate组件  11.2.2 用UserType映射枚举类型  11.2.3 实现CompositeUserType接口  11.2.4 运行本节范例程序  11.3 操纵Blob和Clob类型数据  11.4 小结  11.5 思考题 第12章 ...

    Hibernate_学习总结

    2. **客户化映射类型**:允许开发者自定义映射类型,以满足特殊需求或非标准数据类型的映射,增强了框架的灵活性和适应性。 了解并掌握这些核心概念和操作细节,对于高效利用Hibernate框架进行数据库操作至关重要。...

    Hibernate_3.2.0_符合Java习惯的关系数据库持久化

    HIBERNATE - 符合Java习惯的关系数据库持久化 Hibernate参考文档 3.2 -------------------------------------------------------------------------------- 目录 前言 1. 翻译说明 2. 版权声明 1. Hibernate...

    Hibernate教程

    10.1.7. 隐式多态和其他继承映射混合使用 10.2. 限制 11. 与对象共事 11.1. Hibernate对象状态(object states) 11.2. 使对象持久化 11.3. 装载对象 11.4. 查询 11.4.1. 执行查询 11.4.1.1. 迭代式获取结果...

    Java应用中使用Hibernate[定义].pdf

    在实践中,创建一个持久化类,如`Customer.java`,是使用Hibernate的第一步。这个类通常会包含对应的数据库表字段,如`id`、`name`和`age`。`Customer`类需要实现`Serializable`接口,因为Hibernate在某些操作中会...

    Hibernate+中文文档

    9.1.7. 隐式多态和其他继承映射混合使用 9.2. 限制 10. 与对象共事 10.1. Hibernate对象状态(object states) 10.2. 使对象持久化 10.3. 装载对象 10.4. 查询 10.4.1. 执行查询 10.4.2. 过滤集合 10.4.3. ...

    hibernate3.6 文档(pdf 格式)

    - **映射文件**:使用 Hibernate 映射文件(.hbm.xml 文件)定义 Java 对象和数据库表之间的关系。 - **Hibernate 配置**:设置 Hibernate 的配置文件(hibernate.cfg.xml),定义数据库连接、方言、缓存策略等。 - ...

Global site tag (gtag.js) - Google Analytics