Hibernate多表联合查询解决办法[ZT]

Hibernate
是典型的OPM工具,它将每一个物理表格(Table)映射成为对象(Object),这发挥了面向对象的优势,使设计和开发人员可以从面向对象的角度来进行对数据库
的管理。
     在设计到多表操作时,Hibernate提供了与数据库表关系相对应的对象映射关系,一对一、一对多和多对多在这里都可以通过Hibernate的对象映 射关系(Set等)来实现。这为一般情况下的数据库多表操作提供了便捷途径。关于这方面的介绍已经很多,在这里不再复述。

但是,在有些情况下的多表操作,比如一个统计顾客在2005年的消费总金额的SQL操作如下:
  
sql 代码
  1. select    
  2. b.name count (a.fee) mix(a.chargeBeginTime)  max (a.chargeEndTime)   
  3. from    
  4. charge a, customer b   
  5. where    
  6. a.idCustomer = b.idCustomer and  a.chargeBeginTime >= '2005-01-01'   
  7. and  a.chargeEndTime < '2005-12-31' gourp  by  a.idCustomer  
customer表和charge结构如下:
customer表结构:
+------------+-------------+------+-----+---------+-------+
| Field      | Type        | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| IdCustomer | varchar(32) |      | PRI |         |       |
| Name       | varchar(30) |      |     |         |       |
+------------+-------------+------+-----+---------+-------+
charge表结构:
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| IdCharge        | varchar(32) |      | PRI |         |       |
| Fee             | double      | YES  |     | NULL    |       |
| ChargeTimeBegin | datetime    | YES  |     | NULL    |       |
| ChargeTimeEnd   | datetime    | YES  |     | NULL    |       |
+-----------------+-------------+------+-----+---------+-------+
在Hibernate的自带文档中有类似下面的多表查询操作提示:
  
sql 代码
 
  1. select  new OjbectC(field1, field2,...)  from  ObjectA a, ObjectB b ...  
分析一下可以看出这个操作有两个缺点:
    1)必须声明并创建类ObjectC,根据Hibernate的特点,需要写一个ObjectC.hbm.XML
的PO映射,在只用到创建查询结果的新对象的时候,这个映射可以是个虚的,即可以没有一个真正的数据库表和ObjectC对应,但是这样的一个虚设的逻辑显然已经违背了Hibernate的思想初衷;
    2)这个办法只能查询出但条结果记录并只能创建单个的ObjectC对象,这是很局限的,因此在某些情况下根本不能使用(比如本例)。
    所以,对于本例,上面的方法是行不通的。
其实,仔细看看Hibernate的API,就会发现这个问题很好解决。在net.sf.hibernate包中有下面三个对我们很有用的接口:
1、Interface ScrollableResults
    这个接口类似JDBC
中的ResultSet一样,提供了对返回结果集合的遍历和字段访问方法,如:
    public boolean next
()    游标后移
    public boolean previous
() 游标前移
    public boolean scroll
(int i) 游标移动到指定未知
    public void beforeFirst
() 游标在首记录前
    public void afterLast
() 游标在末记录后
    public Object

[] get
() 将当前记录的字段值以Object对象数组形式返回
    public Object

 get
(int i) 将当前记录的特定字段值以Object对象形式返回
    public Integer

 getInteger
(int col) 将当前记录的特定字段值以Integer对象返回
    public Long

 getLong
(int col) 将当前记录的特定字段值以Long对象返回
    public String

 getText
(int col) 将当前记录的特定字段值以Text对象返回
    public String

 getString
(int col) 将当前记录的特定字段值以String对象返回
    ...等等
2、Interface Query
    Query接口封装了对数据库的查询等操作,在这里,我们使用到它的原因是在于它的scroll()方法可以返回一个ScrollableResults实例:
    public ScrollableResults

 scroll
() 将查询结果以ScrollableResults实例返回,但需要注意的是查询返回的结果其实只是一些id,当需要的时候(比如我们使用 ScrollableResults.next()方法后移游标时)这条需要用到的记录才会被真正初始化(这种技术可以称作:延时初始化)
3、Interface Session
    Session是Hibernate的核心中的核心,通过Session的createQuery()方法,我们能生成一个Query实例:
    public Query

 createQuery
(String

 queryString) 用给出的HQL查询串创建一个Query实例
好了,了解了上面的三个接口,问题就能够很好的解决了。需要如下几个文件:
Customer.Java
                            PO对象
Charge.java                                PO对象
TotalCharge.java                        用于保存统计结果Bean
Customer.hbm.xml                      PO映射
Charge.hbm.xml                          PO映射
TotalChargeDao.java                  统计Dao定义
TotalChargeDaoImpl.java           统计Dao定义实现
DaoFactory.java                         Dao工厂
HibernateSessionFactory.java     Session工厂
因为这里主要讨论的重点是对Customer和Charge的联合查询,所以Customer.java、Charge.java、 Customer.hbm.xml、Charge.hbm.xml四个文件以及TotalChargeDao.java、 DaoFactory.java、HibernateSessionFactory.java的源代码在这里省略掉。
  
TotalCharge.

java 代码
     
 
  1. package  test.bean;  
  2. /**  
  3.  *作者:孙星  
  4.  **/   
  5. public   class  TotalCharge {  
  6.   private  String name;  
  7.   private  Double fee;  
  8.   private  java.util.Date chargeTimeBegin;  
  9.   private  java.util.Date chargeTimeEnd;  
  10.   public  TotalCharge() {  
  11.   }  
  12.   public  String getName() {  
  13.     return  name;  
  14.   }  
  15.   public  TotalCharge(String name, Double fee, java.util.Date chargeTimeBegin,  
  16.                      java.util.Date chargeTimeEnd) {  
  17.     this .name = name;  
  18.     this .fee = fee;  
  19.     this .chargeTimeBegin = chargeTimeBegin;  
  20.     this .chargeTimeEnd = chargeTimeEnd;  
  21.   }  
  22.   public   void  setName(String name) {  
  23.     this .name = name;  
  24.   }  
  25.   public  Double getFee() {  
  26.     return  fee;  
  27.   }  
  28.   public   void  setFee(Double fee) {  
  29.     this .fee = fee;  
  30.   }  
  31.   public  java.util.Date getChargeTimeBegin() {  
  32.     return  chargeTimeBegin;  
  33.   }  
  34.   public   void  setChargeTimeBegin(java.util.Date chargeTimeBegin) {  
  35.     this .chargeTimeBegin = chargeTimeBegin;  
  36.   }  
  37.   public  java.util.Date getChargeTimeEnd() {  
  38.     return  chargeTimeEnd;  
  39.   }  
  40.   public   void  setChargeTimeEnd(java.util.Date chargeTimeEnd) {  
  41.     this .chargeTimeEnd = chargeTimeEnd;  
  42.   }  
  43. }  
TotalChargeDaoImpl.java 代码
  1. package  test.dao.impl;  
  2. import  java.util.*;  
  3. import  test.bean.*;  
  4. import  test.dao.*;  
  5. import  net.sf.hibernate.*;  
  6. /**  
  7.  *作者:孙星  
  8.  **/   
  9. public   class  TotalChargeDaoImple  extends  TotalChargeDao{  
  10.     //下面方法集成自TotalChargeDao   
  11.     public  List statTotalCharge(Date statTimeBegin, Date statTimeEnd)  throws          DaoException{  
  12.         List res = new  Vector(); //将用于存放保存的结果集合   
  13.         Session session = null ;  
  14.         ScrollableResults srs = null ;  
  15.         try {  
  16.             //得到一个Hibernate Session   
  17.             session = HibernateSessionFactory.openSession();  
  18.   
  19.             //下面创建一个匿名Query实例并调用它的scroll()方法返回以    
  20. ScrollableResults形式组织的查询结果  
  21.             srs  
  22. = session.createQuery(“select b.name, count(a.fee)  
  23. mix(a.chargeBeginTime) max(a.chargeEndTime) from charge a, customer b  
  24. where a.idCustomer = b.idCustomer and a.chargeBeginTime >= ? and  
  25. a.chargeEndTime < ? gourp by a.idCustomer“).setDate(0 ,  
  26. statTimeBegin).setDate(1 , statTimeEnd).scroll();  
  27.   
  28.             //将查询结果放入List保存   
  29.             while (srs.next()){  
  30.                 res.add(new  TotalCharge(srs.getString( 0 ), srs,getDouble( 1 ), srs.getDate( 2 ), srs.getDate( 3 )));  
  31.             }  
  32.         }catch (HibernateException he){  
  33.             ;//loging err.....   
  34.             if (srs!= null ){  
  35.                 try {  
  36.                     srs.close();  
  37.                 }catch (Exception e){  
  38.                     ;  
  39.                 }  
  40.             }  
  41.         }finally {  
  42.             try {  
  43.                 session.close();  
  44.             }catch (Exception e){  
  45.                 ;  
  46.             }  
  47.         }  
  48.         return  res;  
  49.     }  
  50. }  

 

看,现在问题解决了。坐下来,喝杯Java吧!

你可能感兴趣的:(java,DAO,sql,Hibernate,bean)