Hibernate本地SQL结果集转换为自定义POJO对象
Hibernate如果用于单表的增删改查,其方便性不言而喻,但很多时候我们需要进行关联查询。这时候Hibernate可能不是太方便了。好在Hibernate提供了本地SQL,允许我们手写SQL语句。
Hibernate之所以不用手写SQL,是因为Hibernate的实体类对象和数据库字段之间有映射关系。而我们自定义的对象和数据库之间没有明显的映射关系。比如:
SQL语句中查询出来的字段一般都是下划线形式的,而我们java对象中一般是驼峰方式。如果用实体类就没问题,但我们这里需要用到自定义的普通POJO对象,这里存在转化问题。
Hibernate提供了一个结果集转换的方法。
query.setResultTransformer(ResultTransformer transformer)。
Hibernate提供了该方法的参数的几种取值
- Transformers.ALIAS_TO_ENTITY_MAP //把输出结果转换成map
- Transformers.TO_LIST //把结果按顺序排进List
- 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对象相关推荐
- Hibernate本地SQL查询SQLQuery
http://callan.iteye.com/blog/156127 使用SQLQuery 对原生SQL查询执行的控制是通过SQLQuery接口进行的,通过执行Session.createSQLQu ...
- 使用HIBERNATE的SQL查询并将结果集自动转换成POJO
在某些场合下,我们可能想使用HIBERNATE的框架提供的SQL查询接口,但是,由于实体没有做映射,HIBERNATE不能把结果集转换成你想要的List<POJO>,本文讨论如何在这种情况 ...
- hibernate将本地SQL查询结果封装成对象
hibernate将本地SQL查询结果封装成对象 不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里, ...
- Hibernate三种状态;query查询;ResultTransformer转换为pojo对象;可以将query语句写在xml中;Criteria查询;ProjectionList总和/f分组等函数
Session操作过程中的pojo对象存在三种状态: 1) 瞬时态:该对象在数据库中没有对应的数据 2) 持久态:数据库中存在该对象对应的数据,同时操作该对象的Session也存在. 3) 游离 ...
- Hibernate之检索方式(HQL/QBC/本地SQL)
一.概述 Hibernate提供了以下几种检索对象的方式 导航对象图:根据已经加载的对象导航到其它对象 OID:按照对象的OID来检索对象 HQL:使用面向对象的HQL查询语句 QBC:使用QBC(Q ...
- Hibernate学习之路(十三):Hibernate中的QBC查询和本地sql操作
什么是hibernate的QBC查询 QBC 查询就是通过使用 Hibernate 提供的 Query By Criteria API 来查询对象,这种 API 封装了 SQL 语句的动态拼装,对查询 ...
- SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话
SQL Server扩展事件(Extended Events)-- 将现有 SQL 跟踪脚本转换为扩展事件会话 如果您具有想要转换为扩展事件会话的现有 SQL 跟踪脚本,则可以使用本主题中的过程创建等 ...
- Hibernate Native SQL查询示例
Hibernate Native SQL查询示例 欢迎使用Hibernate Native SQL Query示例教程.我们在前面的文章中研究了Hibernate查询语言和Hibernate Crit ...
- hibernate 或jpa 中使用 AliasToBeanResultTransformer 自定义类型转换ResultTransformer 下划线转驼峰...
jpa中使用 sql查询时,返回结果直接转为实体bean的实现, 需要自定义一个ResultTransformer,如下, import java.util.Arrays;import org.apa ...
最新文章
- 【OpenCV3】图像最大轮廓检测——cvFindBiggestContour()封装
- X-Magic Pair gcd,剪枝(1600)
- [C++学习笔记](double*)malloc(n * sizeof(double));
- 小学计算机ppt课教案,小学信息技术公开课教案《让幻灯片变得更加漂亮》教学设计与反思...
- 语音对讲软件_三款语音转文字工具,语音输入,高效转换,准确率高
- 送书 | 获得诺贝尔奖之后影响力会下降?绘制精英科学家的职业生涯路线图
- 转载:SharePoint技术资料
- 修改GDAL库支持RPC像方改正模型
- VS2013 ConsoleApplication1.exe”(Win32):无法查找或打开 PDB 文件。
- iphone屏幕镜像如何全屏_苹果投屏有什么方法?使用“屏幕镜像”功能,任意切换大小屏幕...
- 【Android】【架构】【美团猫眼模块化】
- matlab画出鸢尾花数据集散点图尾花,鸢尾花数据集分以及绘制散点矩阵图
- spring boot跳过maven test
- PDF如何转换成EPUB格式
- qt creator编译qt工程时报错:undefined reference to
- Node.js 学习之数据库与身份认证
- 计算机任务计划程序已损坏,Win7-该任务映像已损坏或已篡改。(异常来自HRESULT:0x80041321)解决办法...
- 【100%通过率】华为OD机试真题 JS 实现【最接近最大输出功率的设备 /查找充电设备组合】【2023 Q1 | 200分】
- C语言:va_list的用法
- SDN(软件定义网络)数据平面