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);
然而, 當咱們須要再次查詢BaseDict
中dictTypeCode=009
的記錄時, 須要從新建立一個新的DetachedCriteria. 不然, 會將上次dictTypeCode=006
的條件合併起來. 看下圖:hibernate
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
CriteriaEntries
的迭代器, 經過遍歷刪除迭代器中每個元素, 即實現了清空條件的目的.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(); }