`
wb284551926
  • 浏览: 540032 次
文章分类
社区版块
存档分类
最新评论

使用HIBERNATE的SQL查询并将结果集自动转换成POJO(转载)

 
阅读更多

文章分类:Java编程 在某些场合下,我们可能想使用HIBERNATE的框架提供的SQL查询接口,这时,由于表和实体都可能没有做映射,HIBERNATE不能把结果集转换 成你想要的List<POJO>,本文讨论如何在这种情况下让HIBERNATE直接返回你想的结果。下面是简单的查询封装方法

Java代码
  1. public  List<? extends  BaseModel> findObjectBySql(String queryString,Class<? extends  BaseModel> pojoClass){  
  2.                   //使用SQL构造查询对象,此SQL是可以被JDBC接受的SQL,如SELECT * FROM XXX_TABLE   
  3.         Query query = this .getSession().createSQLQuery(queryString);  
  4.                   //设置结果集转换器,这是本文重点所在   
  5.         query.setResultTransformer(new  EscColumnToBean(pojoClass));  
  6.                   //返回查询结果   
  7.         return  query.list();  
  1. public List<? extends BaseModel> findObjectBySql(String queryString,Class<? extends BaseModel> pojoClass){  
  2.                   //使用SQL构造查询对象,此SQL是可以被JDBC接受的SQL,如SELECT * FROM XXX_TABLE  
  3.         Query query = this.getSession().createSQLQuery(queryString);  
  4.                   //设置结果集转换器,这是本文重点所在  
  5.         query.setResultTransformer(new EscColumnToBean(pojoClass));  
  6.                   //返回查询结果  
  7.         return query.list();  



    上面这个方法很简单,如果查的是USER表,并且pojoClass参数传入的就是USER.class的话,那么返回结果集的就是 List<User>。当然在我的应用中还有查询条件封装,分页和自动查询总行数等逻辑,不想把主题分散,所以给省略了。
     下面是结果集转换器的完整代码

Java代码
  1. package  com.lgdlgd.hibernate;  
  2.   
  3. import  java.lang.reflect.Field;  
  4. import  java.util.List;  
  5.   
  6. import  org.hibernate.HibernateException;  
  7. import  org.hibernate.property.ChainedPropertyAccessor;  
  8. import  org.hibernate.property.PropertyAccessor;  
  9. import  org.hibernate.property.PropertyAccessorFactory;  
  10. import  org.hibernate.property.Setter;  
  11. import  org.hibernate.transform.ResultTransformer;  
  12.   
  13. import  com.esc.common.baseclass.BaseModel;  
  14.   
  15. /**  
  16.  * 自定义的数据库字库转换成POJO  
  17.  */   
  18. public  class  EscColumnToBean implements  ResultTransformer {  
  19.     private  static  final  long  serialVersionUID = 1L;  
  20.     private  final  Class<? extends  BaseModel> resultClass;  
  21.     private  Setter[] setters;  
  22.     private  PropertyAccessor propertyAccessor;  
  23.       
  24.     public  EscColumnToBean(Class<? extends  BaseModel> resultClass) {  
  25.         if (resultClass==nullthrow  new  IllegalArgumentException("resultClass cannot be null" );  
  26.         this .resultClass = resultClass;  
  27.         propertyAccessor = new  ChainedPropertyAccessor(new  PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass,null ), PropertyAccessorFactory.getPropertyAccessor("field" )});        
  28.     }  
  29.   
  30.     //结果转换时,HIBERNATE调用此方法   
  31.     public  Object transformTuple(Object[] tuple, String[] aliases) {  
  32.         Object result;  
  33.           
  34.         try  {  
  35.             if (setters==null ) {//首先初始化,取得目标POJO类的所有SETTER方法   
  36.                 setters = new  Setter[aliases.length];  
  37.                 for  (int  i = 0 ; i < aliases.length; i++) {  
  38.                     String alias = aliases[i];  
  39.                     if (alias != null ) {  
  40.                         //我的逻辑主要是在getSetterByColumnName方法里面,其它都是HIBERNATE的另一个类中COPY的   
  41.                         //这里填充所需要的SETTER方法   
  42.                         setters[i] = getSetterByColumnName(alias);  
  43.                     }  
  44.                 }  
  45.             }  
  46.             result = resultClass.newInstance();  
  47.               
  48.             //这里使用SETTER方法填充POJO对象   
  49.             for  (int  i = 0 ; i < aliases.length; i++) {  
  50.                 if (setters[i]!=null ) {  
  51.                     setters[i].set(result, tuple[i], null );  
  52.                 }  
  53.             }  
  54.         } catch  (InstantiationException e) {  
  55.             throw  new  HibernateException("Could not instantiate resultclass: "  + resultClass.getName());  
  56.         } catch  (IllegalAccessException e) {  
  57.             throw  new  HibernateException("Could not instantiate resultclass: "  + resultClass.getName());  
  58.         }  
  59.           
  60.         return  result;  
  61.     }  
  62.   
  63.     //根据数据库字段名在POJO查找JAVA属性名,参数就是数据库字段名,如:USER_ID   
  64.     private  Setter getSetterByColumnName(String alias) {  
  65.         //取得POJO所有属性名   
  66.         Field[] fields = resultClass.getDeclaredFields();  
  67.         if (fields==null  || fields.length==0 ){  
  68.             throw  new  RuntimeException("实体" +resultClass.getName()+"不含任何属性" );  
  69.         }  
  70.         //把字段名中所有的下杠去除   
  71.         String proName = alias.replaceAll("_""" ).toLowerCase();  
  72.         for  (Field field : fields) {  
  73.             if (field.getName().toLowerCase().equals(proName)){//去除下杠的字段名如果和属性名对得上,就取这个SETTER方法   
  74.                 return  propertyAccessor.getSetter(resultClass, field.getName());  
  75.             }  
  76.         }  
  77.         throw  new  RuntimeException("找不到数据库字段 :" + alias + " 对应的POJO属性或其getter方法,比如数据库字段为USER_ID或USERID,那么JAVA属性应为userId" );  
  78.     }  
  79.   
  80.     @SuppressWarnings ("unchecked" )  
  81.     public  List transformList(List collection) {  
  82.         return  collection;  
  83.     }  
  84.   
  85. }  
  1. package com.lgdlgd.hibernate;  
  2.   
  3. import java.lang.reflect.Field;  
  4. import java.util.List;  
  5.   
  6. import org.hibernate.HibernateException;  
  7. import org.hibernate.property.ChainedPropertyAccessor;  
  8. import org.hibernate.property.PropertyAccessor;  
  9. import org.hibernate.property.PropertyAccessorFactory;  
  10. import org.hibernate.property.Setter;  
  11. import org.hibernate.transform.ResultTransformer;  
  12.   
  13. import com.esc.common.baseclass.BaseModel;  
  14.   
  15. /** 
  16.  * 自定义的数据库字库转换成POJO 
  17.  */  
  18. public class EscColumnToBean implements ResultTransformer {  
  19.     private static final long serialVersionUID = 1L;  
  20.     private final Class<? extends BaseModel> resultClass;  
  21.     private Setter[] setters;  
  22.     private PropertyAccessor propertyAccessor;  
  23.       
  24.     public EscColumnToBean(Class<? extends BaseModel> resultClass) {  
  25.         if(resultClass==nullthrow new IllegalArgumentException("resultClass cannot be null");  
  26.         this.resultClass = resultClass;  
  27.         propertyAccessor = new ChainedPropertyAccessor(new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass,null), PropertyAccessorFactory.getPropertyAccessor("field")});        
  28.     }  
  29.   
  30.     //结果转换时,HIBERNATE调用此方法  
  31.     public Object transformTuple(Object[] tuple, String[] aliases) {  
  32.         Object result;  
  33.           
  34.         try {  
  35.             if(setters==null) {//首先初始化,取得目标POJO类的所有SETTER方法  
  36.                 setters = new Setter[aliases.length];  
  37.                 for (int i = 0; i < aliases.length; i++) {  
  38.                     String alias = aliases[i];  
  39.                     if(alias != null) {  
  40.                         //我的逻辑主要是在getSetterByColumnName方法里面,其它都是HIBERNATE的另一个类中COPY的  
  41.                         //这里填充所需要的SETTER方法  
  42.                         setters[i] = getSetterByColumnName(alias);  
  43.                     }  
  44.                 }  
  45.             }  
  46.             result = resultClass.newInstance();  
  47.               
  48.             //这里使用SETTER方法填充POJO对象  
  49.             for (int i = 0; i < aliases.length; i++) {  
  50.                 if(setters[i]!=null) {  
  51.                     setters[i].set(result, tuple[i], null);  
  52.                 }  
  53.             }  
  54.         } catch (InstantiationException e) {  
  55.             throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());  
  56.         } catch (IllegalAccessException e) {  
  57.             throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());  
  58.         }  
  59.           
  60.         return result;  
  61.     }  
  62.   
  63.     //根据数据库字段名在POJO查找JAVA属性名,参数就是数据库字段名,如:USER_ID  
  64.     private Setter getSetterByColumnName(String alias) {  
  65.         //取得POJO所有属性名  
  66.         Field[] fields = resultClass.getDeclaredFields();  
  67.         if(fields==null || fields.length==0){  
  68.             throw new RuntimeException("实体"+resultClass.getName()+"不含任何属性");  
  69.         }  
  70.         //把字段名中所有的下杠去除  
  71.         String proName = alias.replaceAll("_""").toLowerCase();  
  72.         for (Field field : fields) {  
  73.             if(field.getName().toLowerCase().equals(proName)){//去除下杠的字段名如果和属性名对得上,就取这个SETTER方法  
  74.                 return propertyAccessor.getSetter(resultClass, field.getName());  
  75.             }  
  76.         }  
  77.         throw new RuntimeException("找不到数据库字段 :"+ alias + " 对应的POJO属性或其getter方法,比如数据库字段为USER_ID或USERID,那么JAVA属性应为userId");  
  78.     }  
  79.   
  80.     @SuppressWarnings("unchecked")  
  81.     public List transformList(List collection) {  
  82.         return collection;  
  83.     }  
  84.   
  85. }  



我这个转换器工作的前提是数据库的字段名除了可以含有下杠外,不能再含有其它 POJO对应属性中没有的字符,如USER_ID 对应POJO的userId。
扩展点:
1、可以自定义数据库与POJO属性的对应关系,在查询方法中构造转换器时,通过参数把转换关系传入进来,这样就可实现自由转换了,但请注意这种 转换关系只有非常通用才有价值(上面的转换规则就是:字段名 去除下杠 = JAVA属性名),反之如果每个实体都有自已的转换关系,那就还不如编写一个HIBERNATE的映射文件了。
2、本类没有考虑关联,即自定义的对象属性,但这些都不难实现,有兴趣的朋友可结合我的第一篇文章来实现
注意:HIBERNATE3.25以前(后面的没看),对SQL查询的CHAR类型字段处理不好,只返回一位,且是JAVA的CHAR类型,要修改CharacterType类的代码以返回该类型字段的全值

后记:刚才有朋友说到,HIBERNATE本身也支持这种封装,直接使用HIBERNATE原有的封装:

Java代码
  1. Query query = this .getSession().createSQLQuery(queryString).addEntity(pojoClass);  
  1. Query query = this.getSession().createSQLQuery(queryString).addEntity(pojoClass);  


这样后面就不需要设置结果转换器了,但是这样做的前提是实体必须要有映射

 

原创 :这里我要提示一点,有些时候,有些内容还是不能转换,因为数据类型不一样。这时候就要自己去修改了,将

Object[] tuple,tuple[i]中的变量类型修改,比如tuple[0]中有个变量a 是Long型,但是tuple[i]中的是Bigcimal,

这时候,就要自己写个类比如 chgObject(Object tuple){ a =((BigCimal) tuple[i].getA()).longValue();}

 

原文地址:http://blog.csdn.net/xcl119xcl/article/details/5386703

分享到:
评论

相关推荐

    java6string源码-JdbcMapper:JdbcMapper是一个ORM,可以快速轻松地将普通SQL查询映射到各种POJO(Plai

    查询,并使用它们从不同类型集合的数据库中快速轻松地选择 POJO(Plain Old Java 对象)。 类型安全贯穿始终,因此不需要强制转换或忽略警告。 有两种不同的方法可以实现这一点。 JdbcMapper 在编译时生成代码,...

    支持多数据库的ORM框架ef-orm.zip

    也无需编写代码将这些查询条件转换为SQL/HQL/JPQL。DAO层也不会有老要改来改去的接口和API,几乎可以做到零编码。 对单个对象进行CRUD的操作API现在和Criteria API合并在一起。Session对象可以直接提供原本要...

    xmljava系统源码-memory:超轻量级Java持久化工具:比dbutils更小巧、好用的的持久化工具,支持Oracle&MYSQL

    xml java系统源码 清瘦的记录者: 一个比dbutils更小巧、好用的的持久化工具 1. 概述 1.1 连接、语句和结果集  从上看,其对数据访问层有相当简洁的抽象:1、连接... 获取结果集,就是把ResultSet转换为目标数

    Grails权威指南

     11.2.3 在pojo实体中使用约束  11.2.4 得到sessionfactory对象  11.3 使用spring进行依赖注入  11.3.1 使用grails中的bean  11.3.2 重载bean的定义  11.4 在grails中使用spring控制器  ...

    JAVA程序开发大全---上半部分

    9.2.3 创建Hibernate使用的数据库连接 140 9.2.4 创建SessionFactory类 140 9.2.5 使用Hibernate配置文件编辑器 141 9.2.6 使用反向工程生成持久化对象、映射文件和DAO类 143 9.2.7 使用Hibernate功能 151 9.3 ...

    DWR.xml配置文件说明书(含源码)

    一种不能采用默认方式定义的converter就是Bean Converter,这个是将POJO对象转换成javascript相关的数组,反向也一样.基于安全因素的考虑这种类型的converter不能采用默认的方式实现. 假设有个bean并且通过语句设置成...

    JPA-eclipselink-project:使用 EclipseLink 实现的 JPA 项目示例

    API 提供类似于 SQL 的查询语言,但使用对象而不是数据库中的关系实体。 Java Persistence API 基于实体,这些实体是简单的带注释的 POJO,以及这些实体的管理器 (EntityManager),它提供处理它们的功能(添加、...

    Spring中文帮助文档

    11.5.2. 使用SimpleJdbcInsert来获取自动生成的主键 11.5.3. 指定SimpleJdbcInsert所使用的字段 11.5.4. 使用SqlParameterSource提供参数值 11.5.5. 使用SimpleJdbcCall调用存储过程 11.5.6. 声明SimpleJdbcCall...

    从Java走向Java+EE+.rar

    12.3 使用Hibernate 161 12.4 小结 165 第13章 Struts和Hibernate实例——两个与登录有关的实例 166 13.1 Struts和Hibernate的开发环境配置 166 13.1.1 数据库的安装和管理 166 13.1.2 Hibernate的安装 ...

    Spring API

    11.5.2. 使用SimpleJdbcInsert来获取自动生成的主键 11.5.3. 指定SimpleJdbcInsert所使用的字段 11.5.4. 使用SqlParameterSource提供参数值 11.5.5. 使用SimpleJdbcCall调用存储过程 11.5.6. 声明SimpleJdbcCall...

    springmybatis

    现在运行这个程序,是不是得到查询结果了。恭喜你,环境搭建配置成功,接下来第二章,将讲述基于接口的操作方式,增删改查。 整个工程目录结构如下: 除非申明,文章均为一号门原创,转载请注明本文地址,谢谢! ...

    play framework 框架手册 word 版

    陆续集成,并自动运行测试 - 111 - 16.安全指南 - 112 - Sessions - 112 - 守住你的安全…安全 - 112 - 不要存储关键性的数据 - 112 - 跨站点脚本攻击 - 112 - SQL注入 - 113 - 跨站点请求伪造 - 114 - 17.Play模块和...

    play框架手册

    陆续集成,并自动运行测试 - 111 - 16.安全指南 - 112 - Sessions - 112 - 守住你的安全…安全 - 112 - 不要存储关键性的数据 - 112 - 跨站点脚本攻击 - 112 - SQL注入 - 113 - 跨站点请求伪造 - 114 - 17.Play模块和...

    整理后java开发全套达内学习笔记(含练习)

    注意:默认类型转换(自动类型提升)会丢失精度,但只有三种情况: int&gt;float; long&gt;float; long&gt;double. 看一下他们的有效位就明白。 二进制是无法精确的表示 0.1 的。 进行高精度运算可以用java.math包中...

Global site tag (gtag.js) - Google Analytics