利用反射清空hibernate离线查询对象中的全部条件

hibernate的离线查询对象DetachedCriteria用起来的确非常方便,可是其有一个缺陷:经过·add(条件表达式)方法添加的条件, 会累加, 其实就是存入list中的, 这样若是要执行不一样的查询, 须要不一样的查询条件时, 就须要分别建立不一样的离线查询对象。工具

今天碰到的一个需求中, 一个Action中对同一张表连续查了三次, 每一次用了不一样的离线查询对象. 感受优势麻烦, 就想看看有没有对应的方法清除上次用过不想用的条件表达式. 结果发现并无, 因而, 就本身经过暴力反射的技术, 写了一个小工具方法, 能够实现清除指定离线查询对象中的全部条件表达式源码分析

背景

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

// 建立离线查询对象
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的条件合并起来. 看下图:hibernate

clipboard.png

源码分析

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

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

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

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

代码实现

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

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();
        
    }
相关文章
相关标签/搜索