精通Hibernate:对象关系映射基础

1、持久化类的属性和访问方法
(1)持久化类简介

精通Hibernate:对象关系映射基础

在Hibernate中持久化类的访问方法有两个调用者,一个是Java应用程序,一个是Hibernate。值得注意的是,Java应用程序不能访问持久化类的private类型的getXXX()、setXXX(),而Hibernate没有这样的限制。

(2)基本类型属性和包装类型属性

Java有8种基本类型:byte,short,char,int,long,float,double,boolean;与之对应的Java提供了8种包装类型:Byte,Short,Character,Integer,Long,Float,Double,Boolean。基本类型与包装类型之间可以如下简单转换:

double prD=1;  



//把double基本类型转换成Double包装类型  




Double wrD=new Double(prD);  




//把Double包装类型转换成double基本类型  



prD=wrD.doubleValue(); 

Hibernate两种类型都是支持的。

(3)在持久化类的访问方法中加入程序逻辑

(a)在Customer类的getName()和setName()方法中加入程序逻辑

假如在Customer类中有firstname属性和lastname属性,但是没有name属性,而数据库CUSTOMERS表中只有NAME字段。当Hibernate从数据库中取得了CUSTOMERS表的NAME字段值后,会调用setName()方法,此时应该让Hibernate通过setName()方法来自动设置firstname属性和lastname。故要在setName()方法中加入额外的程序逻辑。

 public String getName(){  



   return firstname+ " "+lastname;  



}  


 



public void setName(String name){  




  StringTokenizer t=new StringTokenizer(name);  



  firstname=t.nextToken();  


  lastname=t.nextToken();  


} 

在映射文件中此时直接映射name即可,无需映射firstname等。

<property name="name" column="NAME"> 

尽管在Customer类中没有定义name属性,由于Hibernate并不会直接访问name属性,而是通过getName()和setName()方法。只要在Customer.hbm.xml文件中映射了name属性,HQL语句就能访问:

Query query=seesion.createQuery("from Customer as c where c.name='Tom'"); 

但是如果把Customer.hbm.xml文件中name属性配置为:

<property name="name" column="NAME" access="field"> 

程序会直接去访问Customer实例中的name属性,就会出现异常。

精通Hibernate:对象关系映射基础

(b)在Customer类的setOrders()方法中加入程序逻辑

假定Customer类中有一个avgPrice属性,表示订单的平均价格,取值为它所关联Order对象的price的平均值。在CUSTOMERS表中没有AVG_PRICE字段。可以如下操作:

public Double getAvgPrice(){  



     return this.avgPrice;  



 }  



 private void setAvgPrice( Double avgPrice ){  




     this.avgPrice = avgPrice;  



 }  



 public Double getTotalPrice(){  




     return this.totalPrice;  



 }  



 private void setTotalPrice( Double totalPrice ){  




     this.totalPrice = totalPrice;  



 }  


 



 public void setOrders( Set orders ){  




   this.orders = orders;  



   calculatePrice();  


 }  



 public Set getOrders(){  




   return orders;  




 }//定义为一个Set  




 private void calculatePrice(){  




     double avgPrice = 0.0;  




     double totalPrice = 0.0;  




     int count=0;  



/迭代计算orders里面所有price  



     if ( getOrders() != null ){  



       Iterator iter = getOrders().iterator();  



       while( iter.hasNext() ){  




         double orderPrice = ((Order)iter.next()).getPrice();  



         totalPrice += orderPrice;  


         count++;  


       }  



       // Set the price for the order from the calcualted value  



       avgPrice=totalPrice/count;  



       setAvgPrice( new Double(avgPrice) );  



     }  


 } 

在Customer.hbm.xml文件不用映射avgPrice,因为Hibernate不会直接访问avgPrice属性,也不会调用getavgPrice()和setavgPrice().

(c)在Customer类的setSex()方法中加入数据验证逻辑

在持久化类的访问方法中,还可以加入数据验证逻辑。

public char getSex(){  



   return this.sex;  



 }  



 public void setSex(char sex){  




     if(sex!='F' && sex!='M'){  




       throw new IllegalArgumentException("Invalid Sex");  



     }  



     this.sex =sex ;  



 } 

(4)设置派生属性
持久化类并非所有属性都直接和表的字段匹配,持久化类的有些属性是可以在运行的时候得出的,这些称作派生属性。正如之前的avgPrice属性,该方案包括两个步骤:

  • 在映射文件中不映射avgPrice属性
  • 在Customer类的setOrders()方法中加入程序逻辑,自动为avgPrice属性赋值。

除了这种方法来设置派生属性,还可以如下解决:

利用<property>元素的formula属性。formula属性用来设置一个SQL表达式,Hibernate将根据它来计算派生属性的值。以Customer类的totalPrice属性为例:

<property name="totalPrice" formula="(select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=ID)"/> 

在Hibernate从数据库中查询Customer对象时,若查询totalPrice,即:

select totalPrice from CUSTOMERS; 

使用formula属性后,上面的查询语句就会自动地被替代成:

select (select sum(o.PRICE) from ORDERS o where o.CUSTOMER_ID=1) from CUSTOMERS; 

如果子句的查询结果为空,那么上述的语句就会出现异常。解决方法是:将totalPrice的属性定义为Double包装类型。

(5)控制insert和update语句

Hibernate在初始化阶段,就会根据映射文件的映射信息,为所有的持久化类定义以下的SQL语句。

精通Hibernate:对象关系映射基础

以上SQL语句中的“?”代表JDBC PreparedStatement中的参数。这些SQL语句都存放在SessionFactory的内置缓存中,当执行Session的save()、update()、delete() 、load()和get()方法的时候,将从缓存中找到对应预定义的SQL语句,再把具体的参数值绑定到该SQL语句中。

精通Hibernate:对象关系映射基础

精通Hibernate:对象关系映射基础

2、创建命名策略

精通Hibernate:对象关系映射基础

还有一直一种方法是实现Hibernate的org.hibernate.cfg.NamingStrategy接口,对于这个接口Hibernate提供了两种参考实现类:org.hibernate.cfg.defaultNamingStrategy和org.hibernate.cfg.ImprovedNamingStrategy类。

MyNamingStrategy.java

package mypack;  



import org.hibernate.cfg.ImprovedNamingStrategy;  




import org.hibernate.util.StringHelper;  




public class MyNamingStrategy extends ImprovedNamingStrategy {  




   public String classToTableName(String className) {  




        return  StringHelper.unqualify(className).toUpperCase()+'S';//classname转化成大写字母+S就是对应的表名  



   }  



   public String propertyToColumnName(String propertyName) {  




       return propertyName.toUpperCase();  



   }  



   public String tableName(String tableName) {  




       return tableName;  



   }  



   public String columnName(String columnName) {  




       return columnName;  



   }  



   public String propertyToTableName(String className, String propertyName) {  




       return classToTableName(className) + '_' +  



            propertyToColumnName(propertyName);  


   }  


} 

精通Hibernate:对象关系映射基础

精通Hibernate:对象关系映射基础

精通Hibernate:对象关系映射基础

使用命名策略后可以更好的将数据库中表名、列名对象化成类中的对象。

精通Hibernate:对象关系映射基础

3、实例

主要的BusinessService.java

相关推荐