hibernate的离线查询对象
DetachedCriteria
用起来的确很是方便,但是其有一个缺陷:通过·add(条件表达式)
方法添加的条件, 会累加, 其实就是存入list中的, 这样如果要执行不同的查询, 需要不同的查询条件时, 就需要分别创建不同的离线查询对象。今天碰到的一个需求中, 一个
Action
中对同一张表连续查了三次, 每一次用了不同的离线查询对象. 感觉优点麻烦, 就想看看有没有对应的方法清除上次用过不想用的条件表达式. 结果发现并没有, 于是, 就自己通过暴力反射的技术, 写了一个小工具方法, 可以实现清除指定离线查询对象中的所有条件表达式。
背景
通常我们在使用离线查询技术时, 会这么使用.
如查询BaseDict
对象对应的表中dictTypeCode=006
的记录.
// 创建离线查询对象
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
的条件合并起来. 看下图:
源码分析
DetachedCriteria dc = DetachedCriteria.forClass(BaseDict.class);
==> 调用构造DetachedCriteria dc = DetachedCriteria.forClass(clazz.getName); // 通过类名构建对象
==>CriteriaImpl(entityName, ...) // 创建Criteria的实现类
注意: 这是实现类会在离线查询对象dc
名为'impl
'属性中持有.
进入CriteriaImpl
会发现, 原来我们add
的所有查询条件会保存在一个叫做:'CriteriaEntries'的ArrayList
中, 并且提供了对应公有方法, 返回该list的Iterator
迭代器.
经过上述分析, 笔者就有思路了:
- 利用公有方法获取
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();
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。