`
uule
  • 浏览: 6359421 次
  • 性别: Icon_minigender_1
  • 来自: 一片神奇的土地
社区版块
存档分类
最新评论

Hibernate3的动态条件查询DetachedCriteria

阅读更多

  在常规的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所有欄位
List users = criteria.list();
Iterator iterator =  users.iterator();
while(iterator.hasNext()) {
    User user = (User) iterator.next();
    System.out.println(user.getId() + user.getName());          
}

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

Criteria只是个容器,如果想要設定查詢條件,則要使用add()方法加入Restrictions的条件限制 ,例如查詢age大於20且小於40的資料:
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.gt("age", new Integer(20)));
criteria.add(Restrictions.lt("age", new Integer(40)));
List users = criteria.list();

您也可以使用逻辑組合來进行查詢,例如結合age等於(eq)20或(or)age為空(isNull)的條件:
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.or(
                   Restrictions.eq("age", new Integer(20)),
                   Restrictions.isNull("age")
               ));
List users = criteria.list();



DetachedCriteria的关联查询:

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

DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
    dc.add(Restrictions.like("stuName", stuName, MatchMode.ANYWHERE));
     
如果要通过Student的Team的teamName查询一个Student记录,很多人都会这么写:
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
    dc.add(Restrictions.like("team.teamName", teamName, MatchMode.ANYWHERE));
     
遗憾的是上述程序报错,说是在Student中找不到team.teamName属性,这是可以理解的。那么如何通过teamName查找Student呢?
可以这么写:
DetachedCriteria dc = DetachedCriteria.forClass(Student.class);
    dc.createAlias("team", "t");
    dc.add(Restrictions.like("t.teamName", teamName, MatchMode.ANYWHERE));
      没错,就是要先建立team的引用,才能用team导航到teamName

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

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


DetachedCriteria:

例子1:如果每个美女都有自己的客户资源(不要想歪了!),那么需要查询拥有客户Gates的美女怎么办?
两种方法:
1:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class).createCriteria("customers");
beautyCriteria.add(Restrictions.eq("name", "Gates")):

2:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class).createAlias("customers", "c");
beautyCriteria.add(Restrictions.eq("c.name", "Gates")):

接着有了新的要求,年纪太大的美女不要,还是查找拥有客户Gates的,条件如下:
DetachedCriteria beautyCriteria = DetachedCriteria.forClass(Beauty.class, "b").;
DetachedCriteria customerCriteria = beautyCriteria.createAlias("customers", c");
beautyCriteria.add(Restrictions.le("b.age", new Long(20))):
customerCriteria.add(Restrictions.eq("c.name", "Gates")):

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


例子2:

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


DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Department.class);
detachedCriteria.add(Restrictions.eq("name", "department"))
                 .createAlias("employees", "e")
                 .add(Restrictions.gt(("e.age"), new Integer(20)));


List  list = this.getHibernateTemplate().findByCriteria(detachedCriteria);

 

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

  SQL:

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

1. 创建一个Criteria 实例
org.hibernate.Criteria接口表示特定持久类的一个查询。Session是 Criteria实例的工厂。
Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();
  
2. 限制结果集内容
一个单独的查询条件是org.hibernate.criterion.Criterion 接口的一个实例。

org.hibernate.criterion.Restrictions类 定义了获得某些内置Criterion类型的工厂方法。

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "Fritz%") )

    .add( Restrictions.between("weight", minWeight, maxWeight) )

    .list();

约束可以按逻辑分组。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "Fritz%") )

    .add( Restrictions.or(

        Restrictions.eq( "age", new Integer(0) ),

        Restrictions.isNull("age")

    ) )

    .list();

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )

    .add( Restrictions.disjunction()

        .add( Restrictions.isNull("age") )

        .add( Restrictions.eq("age", new Integer(0) ) )

        .add( Restrictions.eq("age", new Integer(1) ) )

        .add( Restrictions.eq("age", new Integer(2) ) )

    ) )

    .list();

  

Hibernate提供了相当多的内置criterion类型(Restrictions 子类), 但是尤其有用的是可以允许

你直接使用SQL。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.sql("lower({alias}.name) like lower(?)", "Fritz%",

Hibernate.STRING) )

    .list();

  

{alias}占位符应当被替换为被查询实体的列别名。

Property实例是获得一个条件的另外一种途径。你可以通过调用Property.forName() 创建一个

Property。

  

  Property age = Property.forName("age");

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.disjunction()

        .add( age.isNull() )

        .add( age.eq( new Integer(0) ) )

        .add( age.eq( new Integer(1) ) )

        .add( age.eq( new Integer(2) ) )

    ) )

    .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )

    .list();

  

3. 结果集排序

你可以使用org.hibernate.criterion.Order来为查询结果排序。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "F%")

    .addOrder( Order.asc("name") )

    .addOrder( Order.desc("age") )

    .setMaxResults(50)

    .list();

  

List cats = sess.createCriteria(Cat.class)

    .add( Property.forName("name").like("F%") )

    .addOrder( Property.forName("name").asc() )

    .addOrder( Property.forName("age").desc() )

    .setMaxResults(50)

    .list();

  

4. 关联

你可以使用createCriteria()非常容易的在互相关联的实体间建立 约束。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "F%")

    .createCriteria("kittens")

        .add( Restrictions.like("name", "F%")

    .list();

 

注意第二个 createCriteria()返回一个新的 Criteria实例,该实例引用kittens 集合中的元素。

接下来,替换形态在某些情况下也是很有用的。

  

List cats = sess.createCriteria(Cat.class)

    .createAlias("kittens", "kt")

    .createAlias("mate", "mt")

    .add( Restrictions.eqProperty("kt.name", "mt.name") )

    .list();

 

(createAlias()并不创建一个新的 Criteria实例。)

Cat实例所保存的之前两次查询所返回的kittens集合是 没有被条件预过滤的。如果你希望只获得

符合条件的kittens, 你必须使用returnMaps()。

  

List cats = sess.createCriteria(Cat.class)

    .createCriteria("kittens", "kt")

    .add( Restrictions.eq("name", "F%") )

    .returnMaps()

    .list();

Iterator iter = cats.iterator();

while ( iter.hasNext() ) {

    Map map = (Map) iter.next();

    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);

    Cat kitten = (Cat) map.get("kt");

}

5. 动态关联抓取

你可以使用setFetchMode()在运行时定义动态关联抓取的语义。

  

List cats = sess.createCriteria(Cat.class)

    .add( Restrictions.like("name", "Fritz%") )

    .setFetchMode("mate", FetchMode.EAGER)

    .setFetchMode("kittens", FetchMode.EAGER)

    .list();

  

这个查询可以通过外连接抓取mate和kittens。

  

6. 查询示例

org.hibernate.criterion.Example类允许你通过一个给定实例 构建一个条件查询。

  

Cat cat = new Cat();

cat.setSex('F');

cat.setColor(Color.BLACK);

List results = session.createCriteria(Cat.class)

    .add( Example.create(cat) )

    .list();

 

版本属性、标识符和关联被忽略。默认情况下值为null的属性将被排除。

可以自行调整Example使之更实用。

  

Example example = Example.create(cat)

    .excludeZeroes()           //exclude zero valued properties

    .excludeProperty("color")  //exclude the property named "color"

    .ignoreCase()              //perform case insensitive string comparisons

    .enableLike();             //use like for string comparisons

List results = session.createCriteria(Cat.class)

    .add(example)

    .list();

 

甚至可以使用examples在关联对象上放置条件。

  

List results = session.createCriteria(Cat.class)

    .add( Example.create(cat) )

    .createCriteria("mate")

        .add( Example.create( cat.getMate() ) )

    .list();

 

7. 投影(Projections)、聚合(aggregation)和分组(grouping)

org.hibernate.criterion.Projections是 Projection 的实例工厂。我们通过调用

setProjection()应用投影到一个查询。

  

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.rowCount() )

    .add( Restrictions.eq("color", Color.BLACK) )

    .list();

  

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.projectionList()

        .add( Projections.rowCount() )

        .add( Projections.avg("weight") )

        .add( Projections.max("weight") )

        .add( Projections.groupProperty("color") )

    )

    .list();



在一个条件查询中没有必要显式的使用 "group by" 。某些投影类型就是被定义为 分组投影,他

们也出现在SQL的group by子句中。

可以选择把一个别名指派给一个投影,这样可以使投影值被约束或排序所引用。下面是两种不同的

实现方式:

  

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )

    .addOrder( Order.asc("colr") )

    .list();

 

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.groupProperty("color").as("colr") )

    .addOrder( Order.asc("colr") )

    .list();

  

alias()和as()方法简便的将一个投影实例包装到另外一个 别名的Projection实例中。简而言之,

当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:

  

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.projectionList()

        .add( Projections.rowCount(), "catCountByColor" )

        .add( Projections.avg("weight"), "avgWeight" )

        .add( Projections.max("weight"), "maxWeight" )

        .add( Projections.groupProperty("color"), "color" )

    )

    .addOrder( Order.desc("catCountByColor") )

    .addOrder( Order.desc("avgWeight") )

    .list();

 

List results = session.createCriteria(Domestic.class, "cat")

    .createAlias("kittens", "kit")

    .setProjection( Projections.projectionList()

        .add( Projections.property("cat.name"), "catName" )

        .add( Projections.property("kit.name"), "kitName" )

    )

    .addOrder( Order.asc("catName") )

    .addOrder( Order.asc("kitName") )

    .list();

 

也可以使用Property.forName()来表示投影:

  

List results = session.createCriteria(Cat.class)

    .setProjection( Property.forName("name") )

    .add( Property.forName("color").eq(Color.BLACK) )

    .list();

List results = session.createCriteria(Cat.class)

    .setProjection( Projections.projectionList()

        .add( Projections.rowCount().as("catCountByColor") )

        .add( Property.forName("weight").avg().as("avgWeight") )

        .add( Property.forName("weight").max().as("maxWeight") )

        .add( Property.forName("color").group().as("color" )

    )

    .addOrder( Order.desc("catCountByColor") )

    .addOrder( Order.desc("avgWeight") )

    .list();

 

8. 离线(detached)查询和子查询

DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的 Session来

执行它。

  

DetachedCriteria query = DetachedCriteria.forClass(Cat.class)

    .add( Property.forName("sex").eq('F') );

//创建一个Session

Session session = .;

Transaction txn = session.beginTransaction();

List results = query.getExecutableCriteria(session).setMaxResults(100).list();

txn.commit();

session.close();

 

DetachedCriteria也可以用以表示子查询。条件实例包含子查询可以通过 Subqueries或者

Property获得。

  

DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)

    .setProjection( Property.forName("weight").avg() );

session.createCriteria(Cat.class)

    .add( Property.forName("weight).gt(avgWeight) )

    .list();

DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)

    .setProjection( Property.forName("weight") );

session.createCriteria(Cat.class)

    .add( Subqueries.geAll("weight", weights) )

    .list();

相互关联的子查询也是有可能的:

  

DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")

    .setProjection( Property.forName("weight").avg() )

    .add( Property.forName("cat2.sex").eqProperty("cat.sex") );

session.createCriteria(Cat.class, "cat")

    .add( Property.forName("weight).gt(avgWeightForSex) )

    .list();

  • 大小: 15.2 KB
分享到:
评论

相关推荐

    Hibernate - DetachedCriteria 的完整用法

    使用 DetachedCriteria 可以很方便地根据查询条件来返回查询结果,Spring 框架提供了 `getHibernateTemplate().findByCriteria(detachedCriteria)` 方法来实现这一点。 Criteria 和 DetachedCriteria 均可使用 ...

    Hibernate 使用DetachedCriteria操作

    在DetachedCriteria中定义的查询条件可以在稍后的时间点附加到Session上执行,这使得查询可以脱离当前的Session状态,因此得名“Detached”。这种特性在处理复杂的、跨多个事务的查询时非常有用,同时也可以避免因长...

    DetachedCriteria查询

    DetachedCriteria 是 Hibernate 中的一种离线查询对象,它可以在不依赖 Session 的情况下生成动态 SQL 语句并进行查询。下面是 DetachedCriteria 查询的详细知识点: 创建 DetachedCriteria 对象 DetachedCriteria...

    \Hibernate_query条件查询

    《Hibernate查询条件查询详解》 Hibernate作为Java领域中广受欢迎的对象关系映射(ORM)框架,极大地简化了数据库操作。其强大的查询能力是其核心功能之一。本篇将深入探讨Hibernate的条件查询,帮助开发者更好地...

    Hibernate_Criteria条件查询数据

    在实际开发中,Hibernate Criteria查询提供了很大的便利性,尤其是在处理动态查询和复杂查询时。通过熟练掌握Criteria API,可以编写出更简洁、更易于维护的代码。希望这份资料能帮助你更好地理解和运用Hibernate的...

    Hibernate(24): 为什么用DetachedCriteria不能表连接地取数据?

    在Java的持久化框架Hibernate中,DetachedCriteria是一个强大的查询工具,它允许我们在不与Session交互的情况下构建查询条件。然而,DetachedCriteria在处理复杂的关联查询,尤其是涉及到表连接(JOIN)时,可能存在...

    hibernate中的查询方式

    Criteria API提供了一种更为灵活和强大的查询方式,它基于标准的Java对象模型来构建查询条件,支持动态创建查询条件。 **特点:** - **面向对象:** Criteria API完全基于对象,这使得它更加灵活和强大。 - **动态...

    springMVC+hibernate的条件查询加分页的demo

    在这个“springMVC+hibernate的条件查询加分页的demo”中,我们将探讨如何结合这两个框架实现动态的条件查询和分页功能。 首先,让我们了解一下SpringMVC中的条件查询。在SpringMVC中,通常通过Controller层接收...

    hibernate里面的 两种查询

    同时,HQL支持动态查询,可以根据参数动态构造查询语句,适合于复杂或动态的查询需求。 - **基本结构**:HQL查询通常以`from`开始,后面跟着实体类的名称。可以使用`select`指定返回的结果,`where`后跟查询条件,`...

    Java_Hibernate QBC条件查询对比

    同时,Hibernate还提供了Criteria API,它是QBC的一部分,提供了更多的动态查询功能,可以组合多个条件,甚至可以与DetachedCriteria结合,实现更复杂的查询逻辑。 总结来说,Java_Hibernate中的QBC和HQL各有优势和...

    Hibernate_query查询数据表中的一个字段.

    如果你希望在不打开Session的情况下构建查询条件,可以使用DetachedCriteria: ```java DetachedCriteria detached = DetachedCriteria.forClass(User.class); detached.setProjection(Projections.property(...

    HQL是hibernate自己的一套查询

    3. **平台无关**:由于HQL是基于Hibernate框架的查询语言,因此不受特定数据库的影响,可以在不同的数据库平台上无缝迁移。 4. **灵活性**:HQL支持多种查询方式,包括简单查询、复杂查询、联接查询等。 ### HQL的...

    hibernate的多态查询

    5. **多态查询的实现**:Hibernate支持使用`DetachedCriteria`或`Criteria` API来进行多态查询,通过`createCriteria()`方法指定父类,并使用`add(Restrictions.in("property", values))`等方法来限制查询条件。...

    Hibernate3中文文档

    7. **Criteria查询**:除了HQL,Hibernate还提供了Criteria API,这是一种动态构建查询的方式,可以根据条件构建查询,更加灵活。 8. ** Criteria API的DetachedCriteria**:DetachedCriteria允许在不打开Session的...

    Hibernate的MySql查询.rar

    Criteria API则提供了一种更加面向对象的查询方式,它允许我们构建查询条件并动态地组合它们。以下是如何使用Criteria API来获取所有用户: ```java Session session = HibernateUtil.getSessionFactory()....

    DetachedCriteria使用介绍

    `DetachedCriteria` 是 Hibernate 提供的一种灵活且强大的查询机制,它允许你在脱离 Session 的情况下构建复杂的查询标准,这意味着你可以提前构建查询标准,然后在任何地方执行查询,而无需关心当前是否有 Session...

    hibernate查询方法

    Criteria API的优点在于代码可读性高,且支持动态构建查询条件。 ### 三、QBC(Query By Example) QBC是一种基于实例的查询方式,它允许你通过一个对象实例来定义查询条件。以下是一个使用QBC的例子: ```java ...

    三种查询方式跟踪Hibernate源码

    `org.hibernate.criterion`包中的类如`DetachedCriteria`、`Expression`等用于构建这些条件。源码中,`CriteriaQueryTranslator`负责将Criteria API表达式转化为SQL。 最后,JPA的JPQL(Java Persistence Query ...

    Hibernate的Criteria用法总结

    在Java持久层框架Hibernate中,Criteria API是一种动态构建SQL查询的方法,它允许开发者在运行时构建查询,提供了更面向对象的查询方式。本篇将详细阐述Hibernate Criteria API的使用。 首先,Criteria API由...

    Hibernate_query查询数据表中部分字段.

    在复杂的查询场景下,可以使用DetachedCriteria来预定义查询条件,然后在需要时再与其他查询组合使用。 5. **命名查询(Named Queries)**: 如果某些查询模式经常被使用,可以定义命名查询,将其写入XML映射文件...

Global site tag (gtag.js) - Google Analytics