| Blog信息 |
|
blog名称: 日志总数:1304 评论数量:2242 留言数量:5 访问次数:7643345 建立时间:2006年5月29日 |

| |
|
[Hibernate]手动为HibernateDAO里面的DetachedCriteria的Projection擦屁股 软件技术, 电脑与网络
lhwork 发表于 2006/6/15 11:07:04 |
|
无奈,寻找好的解决方法,把我现在擦屁股的现场记录下来。我用GenericHibernateDAO,慢慢积累下来的,有这几个DetachedCriteria的方法:
public
List findByDetachedCriteriaByPage(
final
DetachedCriteria detachedCriteria,
final
int
pagesize,
final
int
pageno) {
return
getHibernateTemplate() .findByCriteria(detachedCriteria, pagesize
*
pageno, pagesize); }
int
getCountByDetachedCriteria(
final
DetachedCriteria detachedCriteria) { Integer count
=
(Integer) getHibernateTemplate().execute(
new
HibernateCallback() {
public
Object doInHibernate(Session session)
throws
HibernateException { Criteria criteria
=
detachedCriteria.getExecutableCriteria(session);
return
criteria.setProjection(Projections.rowCount()) .uniqueResult(); } },
true
); detachedCriteria.setProjection(
null
);
return
count.intValue(); }
这是一对方法,经常一起用,一开始没有注意,后来发现有副作用。生成一个DetachedCriteria,调用完getCountByDetachedCriteria以后再调用findByDetachedCriteriaByPage返回的结果居然是一个Integer……原
来getCountByDetachedCriteria方法里面对detachedCriteria.getExecutableCriteria
(session)产生的criteria设定了Projection,这也影响到了DetachedCriteria本身,以后再用它作查询都回返回
Projection的结果。现在的解决方法是手动擦屁股,重新set
Null。(我原先以为final关键字会保证detachedCriteria不被修改,后来发现只是引用不能修改,实例本身可以随便修改)请问大家,
有什么更好的解决方案么,我决得复杂一点的话这个detachedCriteria如何能擦除回来?Reply from BJUG Groups by whimet:这个问题在javaeye上已经讨论过:http://www.hibernate.org.cn/viewtopic.php?t=14657你这种情况还简单,若DetachedCriteria中包含排序设置就更不好办。 其实关键问题是DetachedCriteria.getExecutableCriteria返回的Criteria实例中已经包含了投影和排序信息,如果你想先查总数, 就得先去掉这些信息;查完总数,再查实际数据时,又得加上这些信息。而Criteria可没提供对它改来改去的接口。 不过,仔细考察一下DetachedCriteria可以发现,它类似一种暂存了查询条件的值对象,通过与一个session对象结合生成 一个“可执行的”Criteria,相当于先执行session.createCriteria,然后把自己保存的条件设置进去。 既然如此,我干脆自己提供一个类似的类,暂存查询条件,与session结合生成executableCriteria;但我先提供给用户一个只包含 查询条件的Criteria实例,让用户先拿着它去查总数;然后再提供加入投影和排序信息的方法,让用户拿着它去查数据,不就解决问题了。 -------------- 示例代码: MyDetachedCriteria dc = 500)this.width=500'> Criteria c = dc.getExecutableCriteria( session ); //这里的c只包含查询条件,不包括投影和排序 c.setProjection( Projections.rowCount() ); Integer total = (Integer) c.uniqueResult(); //得到总数 dc.fillProjectionSetting( c ); //把dc中保存的投影信息设置进去 dc.fillOrdersSetting( c ); //把dc中保存的排序信息设置进去 List data = c.list(); //取回数据 -------------- MyDetachedCriteria的代码: /** * 单独的值对象,用于暂存与Criteria相关的查询条件,并可与Session结合生成一个可执行的Criteria<br> * <br> * 该类继承自DetachedCriteria只是为了保持接口兼容性,其实与DetachedCriteria没关系 <br> * (之所以叫“Detached”,是指与Session脱离) */ public class MyDetachedCriteria extends DetachedCriteria { private Class entityClass; private ArrayList criterions = new ArrayList(); private ArrayList orders = new ArrayList(); private Projection projection; /** * @param entityClass */ public MyDetachedCriteria( Class entityClass ) { super( entityClass.getName() ); this.entityClass = entityClass; } /** * @see org.hibernate.criterion.DetachedCriteria#add(org.hibernate.criterion.Criterion) */ public DetachedCriteria add( Criterion criterion ) { criterions.add( criterion ); return this; } /** * @see org.hibernate.criterion.DetachedCriteria#addOrder(org.hibernate.criterion.Order) */ public DetachedCriteria addOrder( Order order ) { orders.add( order ); return this; } /** * @see org.hibernate.criterion.DetachedCriteria#setProjection(org.hibernate.criterion.Projection) */ public DetachedCriteria setProjection( Projection projection ) { this.projection = projection; return this; } // --------------------------------------------------------------------------- /** * 根据Session实例创建一个Criteria实例,并填充入此对象自身保存的条件后返回<br> * 注意:返回的Criteria实例不含排序和投影信息,用户需要自己调用fillOrdersSetting、 * fillProjectionSetting填充入排序和投影信息 * * @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session) */ public Criteria getExecutableCriteria( Session session ) { Criteria result = session.createCriteria( entityClass ); for ( Iterator i = criterions.iterator(); i.hasNext(); ) { Criterion criterion = ( Criterion ) i.next(); result.add( criterion ); } return result; } /** * 填充入排序信息设置 * * @param criteria * @return */ public Criteria fillOrdersSetting( Criteria criteria ) { for ( Iterator i = orders.iterator(); i.hasNext(); ) { Order order = ( Order ) i.next(); criteria.addOrder( order ); } return criteria; } /** * 填充入投影信息设置 * * @param criteria * @return */ public Criteria fillProjectionSetting( Criteria criteria ) { criteria.setProjection( projection ); return criteria; } } Update 2006-6-6 20:52:恩,谢谢诸位。想了想还是DetachedCriteria设计的目的和我想要的不一样。DetachedCriteria目前只是为了脱离session就可以构造,而并不是为了反复使用。因
为:1、它里面只包装了一个CriteriaImpl,所以实际上两者生命周期比较一致。而且每次getExecutableCriteria都直接返回
这个CriteriaImpl,而不是重新创建,这就造成了容易被意外修改。
2、它没有提供与add对应的remove方法,这就造成它只能累积而不能擦拭(对于Order),用反射就太脏了。whimet写的这个
MyDetachedCriteria倒是可以解决问题,更符合我们想要复用DetachedCriteria的需求,不过我觉得调用起来接口上不太统
一。Order和Projection一般不用复用,我想就可以不用实现DetachedCriteria接口,干脆修改GenericDAO的方法好
了,写个接受List<Criteria>或者Criteria...的方法对应就可以了。反正觉得DetachedCriteria目前的
实现是不如意,hack它吧……我就想提供remove这些Order和Projection的方法。这里用反射解决了他遇到的Order的问题,大家可以参考,看来DetachedCriteria目前实现的还不够令人满意:关于Hibernate的DetachedCriteria查询的addOrder问题的解决办法
|
|
|