zoukankan      html  css  js  c++  java
  • hibernate离线查询DetachedCriteria清除上次的查询条件

    1 原例概述

    别名重复问题之后,我们还需要解决的问题就是:

    如何清除hibernate的上次查询条件,如果不清除,将会导致上次的查询条件和下次的查询条件合并到了一起。

    上次的查询条件和本次的查询条件合并到了一起。

    解决之前的代码如下:

    public String pageQuery() throws Exception {
            DetachedCriteria dc = pageBean.getDetachedCriteria();
            //每一次分页查询的时候应该先清除之前的条件
            // 动态添加过滤条件
            String addresskey = model.getAddresskey();
            if (StringUtils.isNotBlank(addresskey)) {
                // 添加过滤条件,根据地址关键字模糊查询
                dc.add(Restrictions.like("addresskey", "%" + addresskey + "%"));
            }
    
            Region region = model.getRegion();
            if (region != null) {
                String province = region.getProvince();
                String city = region.getCity();
                String district = region.getDistrict();
                
                //创建别名之前需要判断别名是否存在。
                boolean existAlias = existAlias(dc,null,"r");
                if(!existAlias){//不存在就创建
                    dc.createAlias("region", "r");
                }
                
                if (StringUtils.isNotBlank(province)) {
                    // 添加过滤条件,根据省份模糊查询-----多表关联查询,使用别名方式实现
                    // 参数一:分区对象中关联的区域对象属性名称
                    // 参数二:别名,可以任意
                    dc.add(Restrictions.like("r.province", "%" + province + "%"));
                }
                if (StringUtils.isNotBlank(city)) {
                    // 添加过滤条件,根据市模糊查询-----多表关联查询,使用别名方式实现
                    // 参数一:分区对象中关联的区域对象属性名称
                    // 参数二:别名,可以任意
                    dc.add(Restrictions.like("r.city", "%" + city + "%"));
                }
                if (StringUtils.isNotBlank(district)) {
                    // 添加过滤条件,根据区模糊查询-----多表关联查询,使用别名方式实现
                    // 参数一:分区对象中关联的区域对象属性名称
                    // 参数二:别名,可以任意
                    dc.add(Restrictions.like("r.district", "%" + district + "%"));
                }
            }
            subareaService.pageQuery(pageBean);
            this.java2Json(pageBean,
                    new String[] { "currentPage", "detachedCriteria", "pageSize", "decidedzone", "subareas" });
            return NONE;
        }

    第二次执行上面的代码将不会得到结果:原因是前一次的查询条件和本次的查询条件合并了。

    这个我们可以通过发送的sql语句看出来

    解决上述问题原理就是:本次查询之前需要清除hibernate之前的离线查询条件。

    下面我们来看看上述问题的出现原因和解决办法。

    2 背景

    通常我们在使用离线查询技术时, 会这么使用.
    如查询BaseDict对象对应的表中dictTypeCode=006的记录.

    // 创建离线查询对象
    DetachedCriteria dc = DetachedCriteria.forClass(BaseDict.class);
    // 设置查询条件
    dc.add(Restrictions.eq("dictTypeCode", "006"));
    // 利用hibernateTemplate模板根据离线对象查询数据
    List<BaseDict> list = (List<BaseDict>) getHibernateTemplate().findByCriteria(dc);

    然而, 当我们需要再次查询BaseDictdictTypeCode=009的记录时, 需要重新创建一个新的DetachedCriteria. 否则, 会将上次dictTypeCode=006的条件合并起来. 看下图:

    3 源码分析

    DetachedCriteria dc = DetachedCriteria.forClass(BaseDict.class);
    ==> 调用构造
    DetachedCriteria dc = DetachedCriteria.forClass(clazz.getName); // 通过类名构建对象
    ==>
    CriteriaImpl(entityName, ...) // 创建Criteria的实现类
    注意: 这是实现类会在离线查询对象dc名为'impl'属性中持有.

    进入CriteriaImpl会发现, 原来我们add的所有查询条件会保存在一个叫做:'CriteriaEntries'的ArrayList中, 并且提供了对应公有方法, 返回该list的Iterator迭代器.

    经过上述分析, 笔者就有思路了:

      1. 利用公有方法获取CriteriaEntries的迭代器, 通过遍历删除迭代器中每一个元素, 即实现了清空条件的目的.
      2. 直接简单粗暴, 再次反射, 将dc名为'impl'属性重置, 即new一个新的ArrayList赋给它.

    4 解决上述问题的代码实现

    思路一: 获取迭代器, 遍历删除

        private void eraseCriteria(DetachedCriteria dc) {
            try {
                Field impl = dc.getClass().getDeclaredField("impl");
                impl.setAccessible(true);
    
                // 得到实现类
                CriteriaImpl cimpl = (CriteriaImpl) impl.get(dc);
                
                // 思路一: 遍历criterionEntries, 清空所有
                // 利用实现类的公有方法获取迭代器
                Iterator<CriteriaImpl.CriterionEntry> criterionEntryIterator = cimpl.iterateExpressionEntries();
                while (criterionEntryIterator.hasNext()) {
                    // 删除本元素
                    criterionEntryIterator.remove();
                }
            
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Log.end();
            
        }

    思路二: 直接重置CriteriaEntries

        private void eraseCriteria(DetachedCriteria dc) {
            try {
                Field impl = dc.getClass().getDeclaredField("impl");
                impl.setAccessible(true);
    
                // 得到实现类
                CriteriaImpl cimpl = (CriteriaImpl) impl.get(dc);
                
                // 思路二: 再次反射, 直接将criterionEntries置空.
                // 获取criterionEntries属性
                Field criterionEntries = cimpl.getClass().getDeclaredField("criterionEntries");
                criterionEntries.setAccessible(true);
                // 重置条件list
                criterionEntries.set(cimpl, new ArrayList());
    
            
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            Log.end();
            
        }
  • 相关阅读:
    oracle授权另外一个用户访问自己创建的数据对象
    popupWindow使用详解
    oracle用户管理实例
    oracle用户管理入门
    sqlite数据库修改及升级
    android之listView定位到指定行同时隐藏输入键盘
    oracle数据库常用命令
    Oracle11g安装完成后给用户解锁
    Git学习笔记(一)
    gson使用详解
  • 原文地址:https://www.cnblogs.com/jepson6669/p/8876920.html
Copyright © 2011-2022 走看看