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


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

        不知道大家有没有碰过这种情况,迫于很多情况只能用native SQL来查询(如:复杂统计等),然而使用native查询后,结果会被放到object里,要想拿到对应的数据只能由object来强制转换,真的好烦人。因为工作原因,笔者(sourcefour)正在做大量的统计而每次都要进行强制转换,这其实是很麻烦的。我在想如果native SQL查询结果也能够封装对象就好了,于是狠狠的查看了hibernate文档,终于发现了一件令人高兴的事情——native SQL查询的结果也是可以封装成对象滴(具体请看hibernate文档【第16章】)。这种情况不得不高兴啊,于是动手做实验,结果还是令人兴奋的----成功了(^_^)于是将实验结果整理以备以后用。

    1.     适用对象

    可以将以下几种查询结果用Bean封装起来。通俗点说就是查询出来之后就直接将内容放到了Bean实体里。

    总的来说,使用本地SQL查询出来的结果也可以直接放到Bean里,如以下情况(只能想到这么多):

    直接使用本地(native)SQL查询(废话,说的不就是使用native sql嘛^_^)

    2.     具体实现步骤

    2.1. 实体Bean

    实体Bean的写法和对象Bean的写法是一样的。区别在于该实体Bean是不需要做Hibernate映射的。

    我例子中的Bean如下:

    [java] view plaincopy
     
     
    1. package com.sourcefour.bean;  
    2. /** 
    3.  * 这里说明一下,该Bean中的field没必要一定是数据表中的field。 
    4.  * 而应该是DAO中要查询字段的别名,具体请看例子NativeSqlDao, 
    5.  * 我想你会明白的 
    6.  *  
    7.  * @author sourcefour 
    8.  */  
    9. public class NativeSqlBean {  
    10.     private double maxMos;  
    11.     private double minMos;  
    12.     private double avgMos;  
    13.     private int userCount;  
    14.     private String name;  
    15.   
    16.     public double getMaxMos() {  
    17.         return maxMos;  
    18.     }  
    19.   
    20.     public void setMaxMos(double maxMos) {  
    21.         this.maxMos = maxMos;  
    22.     }  
    23.   
    24.     public double getMinMos() {  
    25.         return minMos;  
    26.     }  
    27.   
    28.     public void setMinMos(double minMos) {  
    29.         this.minMos = minMos;  
    30.     }  
    31.   
    32.     public double getAvgMos() {  
    33.         return avgMos;  
    34.     }  
    35.   
    36.     public void setAvgMos(double avgMos) {  
    37.         this.avgMos = avgMos;  
    38.     }  
    39.   
    40.     public int getUserCount() {  
    41.         return userCount;  
    42.     }  
    43.   
    44.     public void setUserCount(int userCount) {  
    45.         this.userCount = userCount;  
    46.     }  
    47.   
    48.     public String getName() {  
    49.         return name;  
    50.     }  
    51.   
    52.     public void setName(String name) {  
    53.         this.name = name;  
    54.     }  
    55. }  

     

    2.2.  Dao操作

    直接上代码:

    [java] view plaincopy
     
     
    1. package com.sourcefour.dao.base;  
    2.   
    3. import java.sql.SQLException;  
    4. import java.util.List;  
    5.   
    6. import javax.annotation.Resource;  
    7.   
    8. import org.hibernate.HibernateException;  
    9. import org.hibernate.Query;  
    10. import org.hibernate.SQLQuery;  
    11. import org.hibernate.Session;  
    12. import org.hibernate.SessionFactory;  
    13. import org.hibernate.transform.Transformers;  
    14. import org.springframework.orm.hibernate3.HibernateCallback;  
    15. import org.springframework.orm.hibernate3.support.HibernateDaoSupport;  
    16. import org.springframework.transaction.annotation.Propagation;  
    17. import org.springframework.transaction.annotation.Transactional;  
    18.   
    19. /** 
    20.  * @author sourcefour 
    21.  */  
    22. @SuppressWarnings("unchecked")  
    23. @Transactional  
    24. public abstract class BaseDaoSupport<T> extends HibernateDaoSupport {  
    25.   
    26.     @Resource(name = "sessionFactory")  
    27.     public void setSuperSessionFactory(SessionFactory sessionFactory) {  
    28.         super.setSessionFactory(sessionFactory);  
    29.     }  
    30.   
    31.     /** 
    32.      * 使用sql语句进行分页查询 
    33.      *  
    34.      * @param sql 
    35.      *            sql语句 
    36.      * @param values 
    37.      *            参数 
    38.      * @param offSet 
    39.      *            第一条记录序号 >-1 
    40.      * @param pageSize 
    41.      *            每页要显示的记录数 >0 
    42.      * @param beanClass 
    43.      *            将查询结果转换为<tt>T</tt>对象 
    44.      * @param fieldList 
    45.      *            查询Bean的成员变量名称 
    46.      */  
    47.     @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)  
    48.     public List<T> list(final String sql, final Object[] values, final int offSet, final int pageSize,  
    49.             final Class<T> beanClass, final List<String> fieldList) {  
    50.         List<T> list = getHibernateTemplate().executeFind(new HibernateCallback() {  
    51.             public Object doInHibernate(Session session) throws HibernateException, SQLException {  
    52.                 SQLQuery sqlQuery = session.createSQLQuery(sql);  
    53.   
    54.                 // 添加要查询字段的标量  
    55.                 AddScalar.addSclar(sqlQuery, beanClass, fieldList);  
    56.   
    57.                 Query query = sqlQuery;  
    58.   
    59.                 // 转换查询结果为T  
    60.                 if (beanClass != null) {  
    61.                     query.setResultTransformer(Transformers.aliasToBean(beanClass));  
    62.                 }  
    63.   
    64.                 if ((values != null) && values.length > 0) {  
    65.                     int i = 0;  
    66.                     for (Object obj : values) {  
    67.                         query.setParameter(i++, obj);  
    68.                     }  
    69.                 }  
    70.   
    71.                 if (offSet > -1) {  
    72.                     query.setFirstResult(offSet);  
    73.                 }  
    74.   
    75.                 if (pageSize > 0) {  
    76.                     query.setMaxResults(pageSize);  
    77.                 }  
    78.                 return query.list();  
    79.             }  
    80.         });  
    81.         return list;  
    82.     }  
    83. }  

    亮点在代码中注释的两句。其中AddScalar.addSclar是自己写的,具体请看代码:

    [java] view plaincopy
     
     
    1. package com.sourcefour.dao.base;  
    2.   
    3. import java.lang.reflect.Field;  
    4. import java.util.Date;  
    5. import java.util.List;  
    6.   
    7. import org.hibernate.Hibernate;  
    8. import org.hibernate.SQLQuery;  
    9.   
    10. /** 
    11.  * @author sourcefour 
    12.  */  
    13. public class AddScalar {  
    14.     /** 
    15.      * 将field type 和 Hibernate的类型进行了对应。这里其实不是多余的,如果不进行一定的对应可能会有问题。 
    16.      * 问题有两个: 
    17.      *  1. 在oracle中我们可能把一些字段设为NUMBER(%),而在Bean中的字段定的是long。那么查询时可能会报: 
    18.      *     java.math.BeigDecimal不能转换成long等错误 
    19.      *  2. 如果不这样写的话,可能Bean中的field就得是大写的,如:name就得写成NAME,userCount就得写成USERCOUNT 
    20.      *     这样是不是很扯(V_V) 
    21.      *  
    22.      * @param <T> 
    23.      * @param sqlQuery 
    24.      *            SQLQuery 
    25.      * @param clazz 
    26.      *            T.class 
    27.      * @param fieldList 
    28.      *            要查询的成员变量名称 
    29.      */  
    30.     public static <T> void addSclar(SQLQuery sqlQuery, Class<T> clazz, List<String> fieldList) {  
    31.         if (clazz == null) {  
    32.             throw new NullPointerException("[clazz] could not be null!");  
    33.         }  
    34.   
    35.         if ((fieldList != null) && (fieldList.size() > 0)) {  
    36.   
    37.             Field[] fields = clazz.getDeclaredFields();  
    38.   
    39.             for (String fieldName : fieldList) {  
    40.                 for (Field field : fields) {  
    41.                     if (fieldName.equals(field.getName())) {  
    42.                         if ((field.getType() == long.class) || (field.getType() == Long.class)) {  
    43.                             sqlQuery.addScalar(field.getName(), Hibernate.LONG);  
    44.                         } else if ((field.getType() == int.class) || (field.getType() == Integer.class)) {  
    45.                             sqlQuery.addScalar(field.getName(), Hibernate.INTEGER);  
    46.                         } else if ((field.getType() == char.class) || (field.getType() == Character.class)) {  
    47.                             sqlQuery.addScalar(field.getName(), Hibernate.CHARACTER);  
    48.                         } else if ((field.getType() == short.class) || (field.getType() == Short.class)) {  
    49.                             sqlQuery.addScalar(field.getName(), Hibernate.SHORT);  
    50.                         } else if ((field.getType() == double.class) || (field.getType() == Double.class)) {  
    51.                             sqlQuery.addScalar(field.getName(), Hibernate.DOUBLE);  
    52.                         } else if ((field.getType() == float.class) || (field.getType() == Float.class)) {  
    53.                             sqlQuery.addScalar(field.getName(), Hibernate.FLOAT);  
    54.                         } else if ((field.getType() == boolean.class) || (field.getType() == Boolean.class)) {  
    55.                             sqlQuery.addScalar(field.getName(), Hibernate.BOOLEAN);  
    56.                         } else if (field.getType() == String.class) {  
    57.                             sqlQuery.addScalar(field.getName(), Hibernate.STRING);  
    58.                         } else if (field.getType() == Date.class) {  
    59.                             sqlQuery.addScalar(field.getName(), Hibernate.TIMESTAMP);  
    60.                         }  
    61.                     }  
    62.                 }  
    63.             }  
    64.         }  
    65.     }  
    66. }  

    所有的准备工作都做好了,那么就看我们的具体的DAO操作及单元测试。

    具体DAO:

    [java] view plaincopy
     
     
    1. package com.sourcefour.dao;  
    2.   
    3. import java.util.ArrayList;  
    4. import java.util.List;  
    5.   
    6. import org.springframework.stereotype.Repository;  
    7.   
    8. import com.sourcefour.bean.NativeSqlBean;  
    9. import com.sourcefour.dao.base.BaseDaoSupport;  
    10.   
    11. /** 
    12.  * @author sourcefour 
    13.  */  
    14. @Repository  
    15. public class NativeSqlDao extends BaseDaoSupport<NativeSqlBean> {  
    16.     public List<NativeSqlBean> listAll(int offSet, int pageSize) {  
    17.         String sql = "SELECT MAX(t.mos) maxMos, MIN(t.mos) minMos, AVG(t.mos) avgMos, COUNT(t.id) userCount FROM t_native_sql t";  
    18.   
    19.         List<String> fieldList = new ArrayList<String>();  
    20.         fieldList.add("maxMos");  
    21.         fieldList.add("minMos");  
    22.         fieldList.add("avgMos");  
    23.         fieldList.add("userCount");  
    24.   
    25.         return super.list(sql, new Object[] {}, offSet, pageSize, NativeSqlBean.class, fieldList);  
    26.     }  
    27. }  

    说明:sql语句中的别名就是我们Bean中的字段

    Junit测试代码:

    [java] view plaincopy
     
     
    1. package com.sourcefour.test.dao;  
    2.   
    3. import java.util.List;  
    4.   
    5. import org.junit.Assert;  
    6. import org.junit.BeforeClass;  
    7. import org.junit.Test;  
    8. import org.springframework.context.ApplicationContext;  
    9. import org.springframework.context.support.ClassPathXmlApplicationContext;  
    10.   
    11. import com.sourcefour.bean.NativeSqlBean;  
    12. import com.sourcefour.dao.NativeSqlDao;  
    13.   
    14. /** 
    15.  * @author sourcefour 
    16.  */  
    17. public class NativeSqlDaoTest {  
    18.     private static NativeSqlDao nativeSqlDao;  
    19.     private static ApplicationContext applicationContext;  
    20.   
    21.     @BeforeClass  
    22.     public static void setUp() {  
    23.         applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");  
    24.         nativeSqlDao = (NativeSqlDao) applicationContext.getBean("nativeSqlDao");  
    25.     }  
    26.   
    27.     @Test  
    28.     public void testListIntInt() {  
    29.         List<NativeSqlBean> list = nativeSqlDao.listAll(-1, -1);  
    30.         Assert.assertNotNull(list);  
    31.         for (NativeSqlBean nativeSqlBean : list) {  
    32.             System.out.println("maxMos: " + nativeSqlBean.getMaxMos());  
    33.         }  
    34.     }  
    35. }  

    运行结果:

    到了这里应该说一切OK鸟。

    完整的文档,SQL,工程下载地址:CSDN下载

    说明:本说明是关于资源附件的,在资源中附件名称叫做 ‘hibernate将本地SQL查询结果封装成对象(最终)’,其实只有一版,这里只所以叫最终版是因为该附件我上传了好几天传不上去,到最后报告说‘资源已经存在’,但我确实没有看到附件。所以没办法只能改个名字了…………

  • 相关阅读:
    教练技术的小应用
    “货品未动,数据先行”,德邦快递与网易云联合打造“智能物流”
    小论数据分析的方法及思维
    网易蜂巢(云计算基础服务)MongoDB服务重磅来袭
    pdfjs viewer 开发小结
    wap html5播放器和直播开发小结
    MongoDB之我是怎么成为Primary节点的
    MongoDB中WiredTiger的数据可用性设置
    AutoMapper 自动映射工具
    linq 左连接实现两个集合的合并
  • 原文地址:https://www.cnblogs.com/telwanggs/p/5430091.html
Copyright © 2020-2023  润新知