DetachedCriteria

http://uule.iteye.com/blog/947923转载
在常规的Web编程中,有大量的动态条件查询,即用户在网页上面自由选择某些条件,程序根据用户的选择条件,动态生成SQL语句,进行查询。

  针对这种需求,对于分层应用程序来说,Web层需要传递一个查询的条件列表给业务层对象,业务层对象获得这个条件列表之后,然后依次取出条件,构造查询语句。这里的一个难点是条件列表用什么来构造?传统上使用Map,但是这种方式缺陷很大,Map可以传递的信息非常有限,只能传递name和value,无法传递究竟要做怎样的条件运算,究竟是大于,小于,like,还是其它的什么,业务层对象必须确切掌握每条entry的隐含条件。因此一旦隐含条件改变,业务层对象的查询构造算法必须相应修改,但是这种查询条件的改变是隐式约定的,而不是程序代码约束的,因此非常容易出错。

   DetachedCriteria可以解决这个问题,即在web层,程序员使用DetachedCriteria来构造查询条件,然后将这个 DetachedCriteria作为方法调用参数传递给业务层对象。而业务层对象获得DetachedCriteria之后,可以在session范围内直接构造Criteria,进行查询。就此,查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦,非常完美!

Criteria 和 DetachedCriteria 的主要区别在于创建的形式不一样, Criteria 是在线的,所以它是由 hibernate Session 进行创建的;而 DetachedCriteria 是离线的,创建时无需Session ,DetachedCriteria 提供了 2 个静态方法 forClass(Class) 或 forEntityName(Name)进行DetachedCriteria 实例的创建。
spring 的框架提供getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria 来返回查询结果。

Criteria:
查詢User表格中的所有資料:

Criteria criteria = session.createCriteria(User.class);

// 查詢user所有欄位

<code class="hljs avrasm has-numbering">List users = criteria<span class="hljs-preprocessor">.list</span>()<span class="hljs-comment">;</span>
Iterator iterator =  users<span class="hljs-preprocessor">.iterator</span>()<span class="hljs-comment">;</span>
while(iterator<span class="hljs-preprocessor">.hasNext</span>()) {
    User user = (User) iterator<span class="hljs-preprocessor">.next</span>()<span class="hljs-comment">;</span>
    System<span class="hljs-preprocessor">.out</span><span class="hljs-preprocessor">.println</span>(user<span class="hljs-preprocessor">.getId</span>() + user<span class="hljs-preprocessor">.getName</span>())<span class="hljs-comment">;          </span>
}</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

Hibernate实际上使用以下的SQL來查詢:
select this_.id as id0_, this_.name as name0_0_ from user this_

Criteria只是个容器,如果想要設定查詢條件,則要使用add()方法加入Restrictions的条件限制 ,例如查詢age大於20且小於40的資料:

<code class="hljs lasso has-numbering">Criteria criteria <span class="hljs-subst">=</span> session<span class="hljs-built_in">.</span>createCriteria(User<span class="hljs-built_in">.</span>class);
criteria<span class="hljs-built_in">.</span>add(Restrictions<span class="hljs-built_in">.</span><span class="hljs-literal">gt</span>(<span class="hljs-string">"age"</span>, <span class="hljs-literal">new</span> <span class="hljs-built_in">Integer</span>(<span class="hljs-number">20</span>)));
criteria<span class="hljs-built_in">.</span>add(Restrictions<span class="hljs-built_in">.</span><span class="hljs-literal">lt</span>(<span class="hljs-string">"age"</span>, <span class="hljs-literal">new</span> <span class="hljs-built_in">Integer</span>(<span class="hljs-number">40</span>)));
<span class="hljs-built_in">List</span> users <span class="hljs-subst">=</span> criteria<span class="hljs-built_in">.</span><span class="hljs-built_in">list</span>();</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

您也可以使用逻辑組合來进行查詢,例如結合age等於(eq)20或(or)age為空(isNull)的條件:

<code class="hljs avrasm has-numbering">Criteria criteria = session<span class="hljs-preprocessor">.createCriteria</span>(User<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
criteria<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.or</span>(
                   Restrictions<span class="hljs-preprocessor">.eq</span>(<span class="hljs-string">"age"</span>, new Integer(<span class="hljs-number">20</span>)),
                   Restrictions<span class="hljs-preprocessor">.isNull</span>(<span class="hljs-string">"age"</span>)
               ))<span class="hljs-comment">;</span>
List users = criteria<span class="hljs-preprocessor">.list</span>()<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>

DetachedCriteria的关联查询:

假设要通过stuName查询一个学生Student记录,可以如下:

<code class="hljs avrasm has-numbering">DetachedCriteria dc = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Student<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
    dc<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.like</span>(<span class="hljs-string">"stuName"</span>, stuName, MatchMode<span class="hljs-preprocessor">.ANYWHERE</span>))<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul>

如果要通过Student的Team的teamName查询一个Student记录,很多人都会这么写:

<code class="hljs avrasm has-numbering">DetachedCriteria dc = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Student<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
    dc<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.like</span>(<span class="hljs-string">"team.teamName"</span>, teamName, MatchMode<span class="hljs-preprocessor">.ANYWHERE</span>))<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul>

遗憾的是上述程序报错,说是在Student中找不到team.teamName属性,这是可以理解的。那么如何通过teamName查找Student呢?
可以这么写:

<code class="hljs avrasm has-numbering">DetachedCriteria dc = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Student<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
    dc<span class="hljs-preprocessor">.createAlias</span>(<span class="hljs-string">"team"</span>, <span class="hljs-string">"t"</span>)<span class="hljs-comment">;</span>
    dc<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.like</span>(<span class="hljs-string">"t.teamName"</span>, teamName, MatchMode<span class="hljs-preprocessor">.ANYWHERE</span>))<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li></ul>

没错,就是要先建立team的引用,才能用team导航到teamName 。

这里有一个特殊情况,如果是对引用对象的id查询,则可以不用建立引用,也就是可以不调用createAlias()语句,如下所示:

<code class="hljs avrasm has-numbering">DetachedCriteria dc = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Student<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
    dc<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.like</span>(<span class="hljs-string">"team.id"</span>, teamId, MatchMode<span class="hljs-preprocessor">.ANYWHERE</span>))<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li></ul>

据我个人的经验,team后只能跟其主键属性,比较其他属性要用别名。此主键属性可以用“id”字符来指代,也可以用team的主键属性来指代。换句话说,我的Student类的类主键“stuId”,不管是在HQL还是在QBC中,都可以用stu.id来指代stu.stuId。在这里可以看出 “id”字符的特殊性。上述是个人观点,并未得到确实的证实。

DetachedCriteria:

例子1:如果每个美女都有自己的客户资源(不要想歪了!),那么需要查询拥有客户Gates的美女怎么办?
两种方法:

<code class="hljs avrasm has-numbering"><span class="hljs-number">1</span>:
DetachedCriteria beautyCriteria = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Beauty<span class="hljs-preprocessor">.class</span>)<span class="hljs-preprocessor">.createCriteria</span>(<span class="hljs-string">"customers"</span>)<span class="hljs-comment">;</span>
beautyCriteria<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.eq</span>(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Gates"</span>)):

<span class="hljs-number">2</span>:
DetachedCriteria beautyCriteria = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Beauty<span class="hljs-preprocessor">.class</span>)<span class="hljs-preprocessor">.createAlias</span>(<span class="hljs-string">"customers"</span>, <span class="hljs-string">"c"</span>)<span class="hljs-comment">;</span>
beautyCriteria<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.eq</span>(<span class="hljs-string">"c.name"</span>, <span class="hljs-string">"Gates"</span>)):</code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

接着有了新的要求,年纪太大的美女不要,还是查找拥有客户Gates的,条件如下:

<code class="hljs applescript has-numbering">DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.<span class="hljs-type">class</span>, <span class="hljs-string">"b"</span>).;
DetachedCriteria customerCriteria = beautyCriteria.createAlias(<span class="hljs-string">"customers"</span>, c<span class="hljs-string">");
beautyCriteria.add(Restrictions.le("</span>b.age<span class="hljs-string">", new Long(20))):
customerCriteria.add(Restrictions.eq("</span>c.<span class="hljs-property">name</span><span class="hljs-string">", "</span>Gates<span class="hljs-string">")):</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li></ul>

关于Criteria更详细的资料,Hibernate的源代码和测试是最好的文档。
Criteria的缺点?DBA很生气,后果很严重。

例子2:

Department和Employee是一对多关联,查询条件为:
  名称是“department”开发部门;
  部门里面的雇员年龄大于20岁;

<code class="hljs avrasm has-numbering">DetachedCriteria detachedCriteria = DetachedCriteria<span class="hljs-preprocessor">.forClass</span>(Department<span class="hljs-preprocessor">.class</span>)<span class="hljs-comment">;</span>
detachedCriteria<span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.eq</span>(<span class="hljs-string">"name"</span>, <span class="hljs-string">"department"</span>))
                 <span class="hljs-preprocessor">.createAlias</span>(<span class="hljs-string">"employees"</span>, <span class="hljs-string">"e"</span>)
                 <span class="hljs-preprocessor">.add</span>(Restrictions<span class="hljs-preprocessor">.gt</span>((<span class="hljs-string">"e.age"</span>), new Integer(<span class="hljs-number">20</span>)))<span class="hljs-comment">;</span>


List  list = this<span class="hljs-preprocessor">.getHibernateTemplate</span>()<span class="hljs-preprocessor">.findByCriteria</span>(detachedCriteria)<span class="hljs-comment">;</span></code><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul><ul class="pre-numbering" style=""><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li></ul>

Java代码 复制代码 收藏代码

detachedCriteria.add(Expression.like("citycode", markuplayer8.getCitycode(),MatchMode.ANYWHERE));  

[java] view plaincopy

detachedCriteria.add(Expression.like("citycode", markuplayer8.getCitycode(),MatchMode.ANYWHERE));  

SQL:
Java代码 复制代码 收藏代码

if(startdate!=null && !startdate.equals("") && enddate!=null && !enddate.equals("")){   
            StringBuffer sb = new StringBuffer();   
            sb.append("enddate >='" + enddate + "' and '"+startdate+"' <= startdate");   
            detachedCriteria.add(Expression.sql(sb.toString()));   
        }   
        List<Markuplayer8> markuplayerList = this.getHibernateTemplate().findByCriteria(detachedCriteria);  

[java] view plaincopy

if(startdate!=null && !startdate.equals("") && enddate!=null && !enddate.equals("")){  
            StringBuffer sb = new StringBuffer();  
            sb.append("enddate >='" + enddate + "' and '"+startdate+"' <= startdate");  
            detachedCriteria.add(Expression.sql(sb.toString()));  
        }  
        List<Markuplayer8> markuplayerList = this.getHibernateTemplate().findByCriteria(detachedCriteria);  

重要:

http://dev.yesky.com/241/2033241.shtml

http://www.tup.com.cn/Resource/tsyz/027541-01.txt

http://www.blogjava.net/hilor/archive/2007/09/14/145172.html

很全的例子:http://blog.csdn.net/kjfcpua/archive/2009/06/21/4287248.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值