Hibernate如果用于单表的增删改查,其方便性不言而喻,但很多时候我们需要进行关联查询。这时候Hibernate可能不是太方便了。好在Hibernate提供了本地SQL,允许我们手写SQL语句。

Hibernate之所以不用手写SQL,是因为Hibernate的实体类对象和数据库字段之间有映射关系。而我们自定义的对象和数据库之间没有明显的映射关系。比如:

SQL语句中查询出来的字段一般都是下划线形式的,而我们java对象中一般是驼峰方式。如果用实体类就没问题,但我们这里需要用到自定义的普通POJO对象,这里存在转化问题。

Hibernate提供了一个结果集转换的方法。

query.setResultTransformer(ResultTransformer transformer)。

Hibernate提供了该方法的参数的几种取值

  1. Transformers.ALIAS_TO_ENTITY_MAP //把输出结果转换成map
  2. Transformers.TO_LIST //把结果按顺序排进List
  3. Transformers.aliasToBean(target) //把结果通过setter方法注入到指定的对象属性中

这里第三种比较接近对象转换了。但第三种只是把结果集用自定义对象去接收了,这里还是要求自定义对象的字段要和结果集的字段要能对应上了。所以我们可以考虑参照相关代码,实现数据库字段到java对象之间的转换。

使用的时候也很方便setResultTransformer(new ColumnToBean(targetObject.getClass())) 即可

详细代码如下(注意:以下代码在Hibernate4.3.5.Final版本下测试通过,由于Hibernate版本升级改动太大,现已知在5.0版本下部分类名称以及包名都发生了变动,需要做些改动才行,具体可以参考我写的另一篇文章,链接地址https://blog.csdn.net/lichuangcsdn/article/details/88063953):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Field;
import java.sql.Clob;
import java.sql.SQLException;
import java.util.List;import org.hibernate.HibernateException;
import org.hibernate.property.ChainedPropertyAccessor;
import org.hibernate.property.PropertyAccessor;
import org.hibernate.property.PropertyAccessorFactory;
import org.hibernate.property.Setter;
import org.hibernate.transform.ResultTransformer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ColumnToBean implements ResultTransformer {private static final Logger logger = LoggerFactory.getLogger(ColumnToBean.class);private static final long serialVersionUID = 1L;private final Class<?> resultClass;private Setter[] setters;private PropertyAccessor propertyAccessor;public ColumnToBean(Class<?> resultClass) {if (resultClass == null)throw new IllegalArgumentException("resultClass cannot be null");this.resultClass = resultClass;propertyAccessor = new ChainedPropertyAccessor(new PropertyAccessor[] { PropertyAccessorFactory.getPropertyAccessor(resultClass, null),PropertyAccessorFactory.getPropertyAccessor("field") });}/*** 结果转换时,HIBERNATE调用此方法* * @param tuple* @param aliases* @return*/public Object transformTuple(Object[] tuple, String[] aliases) {Object result;try {if (setters == null) {// 首先初始化,取得目标POJO类的所有SETTER方法setters = new Setter[aliases.length];for (int i = 0; i < aliases.length; i++) {String alias = aliases[i];if (alias != null) {if (alias.toUpperCase().equals("ROWNUM_")) {//rownum_不是数据库字段continue;}// 逻辑主要是在getSetterByColumnName方法里面,其它都是HIBERNATE的另一个类中COPY的// 这里填充所需要的SETTER方法setters[i] = getSetterByColumnName(alias);}}}result = resultClass.newInstance();// 这里使用SETTER方法填充POJO对象for (int i = 0; i < aliases.length; i++) {if (setters[i] != null && tuple[i]!=null) {Class<?> param= setters[i].getMethod().getParameterTypes()[0];  Class<?> tupleClass = tuple[i].getClass();  //若目标参数类型和当前参数类型不匹配 ,尝试进行转换  if(!param.equals(tupleClass)){  if(Number.class.isAssignableFrom((tupleClass))){  Number num = (Number)tuple[i];  if(Long.class.equals(param)){  setters[i].set(result, num.longValue(), null);  }else if(Integer.class.equals(param)){  setters[i].set(result, num.intValue(), null);  }else if(Boolean.class.equals(param)){  setters[i].set(result, num.intValue()==1, null);  }else if(Float.class.equals(param)){  setters[i].set(result, num.floatValue(), null); }else if(Double.class.equals(param)){  setters[i].set(result, num.doubleValue(), null);//枚举类型转换  }else if(param.isEnum()){  setters[i].set(result, param.getEnumConstants()[num.intValue()],null);  }  //如果tuple为参数的子类,直接设置  //如java.util.Date; java.sql.Date;  }else if(param.isAssignableFrom(tupleClass)){  setters[i].set(result, tuple[i], null);//处理数据库类型定义为大字段Clob的数据,将其转换成字符串类型}else if(tuple[i] instanceof Clob){Clob clob = (Clob) tuple[i];setters[i].set(result, clobToString(clob), null);}else {logger.error("不支持转换的类型:"+tuple[i].getClass());}}else{  setters[i].set(result, tuple[i], null);  }}}} catch (InstantiationException e) {throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());} catch (IllegalAccessException e) {throw new HibernateException("Could not instantiate resultclass: " + resultClass.getName());}return result;}/*** 根据数据库字段名在POJO查找JAVA属性名,参数就是数据库字段名,如:USER_ID* * @param alias* @return*/private Setter getSetterByColumnName(String alias) {// 取得POJO所有属性名Field[] fields = resultClass.getDeclaredFields();if (fields == null || fields.length == 0) {throw new RuntimeException("实体" + resultClass.getName() + "不含任何属性");}// 把字段名中所有的下杠去除String proName = alias.replaceAll("_", "").toLowerCase();for (Field field : fields) {if (field.getName().toLowerCase().equals(proName)) {// 去除下杠的字段名如果和属性名对得上,就取这个SETTER方法return propertyAccessor.getSetter(resultClass, field.getName());}}throw new RuntimeException("找不到数据库字段 :" + alias + " 对应的POJO属性或其getter方法");}@SuppressWarnings("rawtypes")@Overridepublic List transformList(List arg0) {return arg0;}/*** 将Clob类型数据转换成字符串* @param clob* @return*/public static String clobToString(Clob clob) {String reString = "";try {Reader is = null;is = clob.getCharacterStream();// 得到流BufferedReader br = new BufferedReader(is);String s = null;s = br.readLine();StringBuffer sb = new StringBuffer();while (s != null) {//执行循环将字符串全部取出付值给StringBuffer由StringBuffer转成STRINGsb.append(s);s = br.readLine();}reString = sb.toString();} catch (SQLException | IOException e) {logger.error("获取大字段内容失败",e);}return reString;}
}

Hibernate本地SQL结果集转换为自定义POJO对象相关推荐

  1. Hibernate本地SQL查询SQLQuery

    http://callan.iteye.com/blog/156127 使用SQLQuery 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQu ...

  2. 使用HIBERNATE的SQL查询并将结果集自动转换成POJO

    在某些场合下,我们可能想使用HIBERNATE的框架提供的SQL查询接口,但是,由于实体没有做映射,HIBERNATE不能把结果集转换成你想要的List<POJO>,本文讨论如何在这种情况 ...

  3. hibernate将本地SQL查询结果封装成对象

    hibernate将本地SQL查询结果封装成对象 不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里, ...

  4. Hibernate三种状态;query查询;ResultTransformer转换为pojo对象;可以将query语句写在xml中;Criteria查询;ProjectionList总和/f分组等函数

    Session操作过程中的pojo对象存在三种状态: 1)  瞬时态:该对象在数据库中没有对应的数据 2)  持久态:数据库中存在该对象对应的数据,同时操作该对象的Session也存在. 3)  游离 ...

  5. Hibernate之检索方式(HQL/QBC/本地SQL)

    一.概述 Hibernate提供了以下几种检索对象的方式 导航对象图:根据已经加载的对象导航到其它对象 OID:按照对象的OID来检索对象 HQL:使用面向对象的HQL查询语句 QBC:使用QBC(Q ...

  6. Hibernate学习之路(十三):Hibernate中的QBC查询和本地sql操作

    什么是hibernate的QBC查询 QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询 ...

  7. SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话

    SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话 如果您具有想要转换为扩展事件会话的现有 SQL 跟踪脚本,则可以使用本主题中的过程创建等 ...

  8. Hibernate Native SQL查询示例

    Hibernate Native SQL查询示例 欢迎使用Hibernate Native SQL Query示例教程.我们在前面的文章中研究了Hibernate查询语言和Hibernate Crit ...

  9. hibernate 或jpa 中使用 AliasToBeanResultTransformer 自定义类型转换ResultTransformer 下划线转驼峰...

    jpa中使用 sql查询时,返回结果直接转为实体bean的实现, 需要自定义一个ResultTransformer,如下, import java.util.Arrays;import org.apa ...

最新文章

  1. python实现编译器连接器_Python连接器
  2. php如何表格中的变为超链接,php中将网址转换为超链接的函数
  3. 利用GitHub搭建一个酷炫免费的个人博客
  4. python cprofile_python 中 cprofile 分析 多进程程序
  5. POJ读书笔记6.1 - 约瑟夫问题 2746
  6. 诹图系列(3): 条形图
  7. 利用计算机计算问题的案例,两个基于计算思维培养的高中信息技术教学案例
  8. 固态加装机械计算机不显示,笔记本电脑装了固态硬盘,机械硬盘却无法识别
  9. 这位程序员的桌面是我见过最漂亮的了
  10. 前K个高频元素[小根堆和大根堆的使用]
  11. Struts2的学习 主要是知识点和基础知识
  12. 基于Huffman编码的C语言解压缩文件程序
  13. Java中「与运算,或运算,异或运算,取反运算。」
  14. 网络爬虫---用urllib模块爬取京东笔记本电脑的数据、并对其做一个可视化
  15. 清除IE浏览器input后面的删除图标
  16. a标签与button按钮
  17. You have new mail in /var/spool/mail/root
  18. [iTerm] 终端 iTerm2 的简单使用
  19. thinkpad DS-8A8SH光驱 升级 KU54 固件后不读盘的解决办法
  20. sql替换或删除数据库中某字段中的特定字符

热门文章

  1. 触摸屏手机的工作原理是怎样的?
  2. 关于MySQL联合索引和优化军规
  3. 视频/音频(H.264,mp4)的基础参数
  4. 数模分析第五天---判别分析
  5. VRP_SA-模拟退火
  6. java对一些文件格式的操作(读写)
  7. 单点登录(SSO)解决方案介绍
  8. 开源机器人库orocos KDL 学习笔记(五):Inverse Kinematric
  9. os.path.dirname()用法
  10. StringBuffer的使用