zoukankan      html  css  js  c++  java
  • 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所有欄位
    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);

    Java代码 复制代码 收藏代码
    1. detachedCriteria.add(Expression.like("citycode", markuplayer8.getCitycode(),MatchMode.ANYWHERE));  
    [java] view plaincopy
     
    1. detachedCriteria.add(Expression.like("citycode", markuplayer8.getCitycode(),MatchMode.ANYWHERE));  

      SQL:

    Java代码 复制代码 收藏代码
    1. if(startdate!=null && !startdate.equals("") && enddate!=null && !enddate.equals("")){   
    2.             StringBuffer sb = new StringBuffer();   
    3.             sb.append("enddate >='" + enddate + "' and '"+startdate+"' <= startdate");   
    4.             detachedCriteria.add(Expression.sql(sb.toString()));   
    5.         }   
    6.         List<Markuplayer8> markuplayerList = this.getHibernateTemplate().findByCriteria(detachedCriteria);  
    [java] view plaincopy
     
    1. if(startdate!=null && !startdate.equals("") && enddate!=null && !enddate.equals("")){  
    2.             StringBuffer sb = new StringBuffer();  
    3.             sb.append("enddate >='" + enddate + "' and '"+startdate+"' <= startdate");  
    4.             detachedCriteria.add(Expression.sql(sb.toString()));  
    5.         }  
    6.         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();

  • 相关阅读:
    [SDOi2012]Longge的问题(洛谷 2303)
    Biorhythms(信息学奥赛一本通 1639)
    【NOI2002】荒岛野人(信息学奥赛一本通 1637)(洛谷 2421)
    青蛙的约会(信息学奥赛一本通 1631)(洛谷 1516)
    负数求余究竟怎么求???
    X-factor Chain(信息学奥赛一本通 1628)
    同余问题2(超详细!!!)
    map函数怎么用咧↓↓↓
    同余问题1(超详细!!!)
    python -- 连接 orclae cx_Oracle的使用 二
  • 原文地址:https://www.cnblogs.com/HEWU10/p/4725347.html
Copyright © 2011-2022 走看看