利用反射清空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();
        
    }
相關文章
相關標籤/搜索