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. 【OpenCV3】图像最大轮廓检测——cvFindBiggestContour()封装
  2. X-Magic Pair gcd,剪枝(1600)
  3. [C++学习笔记](double*)malloc(n * sizeof(double));
  4. 小学计算机ppt课教案,小学信息技术公开课教案《让幻灯片变得更加漂亮》教学设计与反思...
  5. 语音对讲软件_三款语音转文字工具,语音输入,高效转换,准确率高
  6. 送书 | 获得诺贝尔奖之后影响力会下降?绘制精英科学家的职业生涯路线图
  7. 转载:SharePoint技术资料
  8. 修改GDAL库支持RPC像方改正模型
  9. VS2013 ConsoleApplication1.exe”(Win32):无法查找或打开 PDB 文件。
  10. iphone屏幕镜像如何全屏_苹果投屏有什么方法?使用“屏幕镜像”功能,任意切换大小屏幕...
  11. 【Android】【架构】【美团猫眼模块化】
  12. matlab画出鸢尾花数据集散点图尾花,鸢尾花数据集分以及绘制散点矩阵图
  13. spring boot跳过maven test
  14. PDF如何转换成EPUB格式
  15. qt creator编译qt工程时报错:undefined reference to
  16. Node.js 学习之数据库与身份认证
  17. 计算机任务计划程序已损坏,Win7-该任务映像已损坏或已篡改。(异常来自HRESULT:0x80041321)解决办法...
  18. 【100%通过率】华为OD机试真题 JS 实现【最接近最大输出功率的设备 /查找充电设备组合】【2023 Q1 | 200分】
  19. C语言:va_list的用法
  20. SDN(软件定义网络)数据平面

热门文章

  1. 如何用matlab实现小波变换
  2. CSS深入理解z-index(z-index相关知识总结)
  3. Python的人工智能模拟框架
  4. 单点登录(SSO)解决方案介绍
  5. 安卓实现下拉刷新上拉加载
  6. 韩国李世龙19岁当爹 与洪瑛琦姐弟恋开花结果
  7. 如何给老婆解释什么是Restful
  8. 学习win32汇编指令:lea和offset
  9. 【Redis】技术评审要点
  10. 搭建大型分布式服务(二十五)如何将应用部署到TKE容器集群?