Hibernate之DetachedCriteria、Criteria

2017-04-21 19:39

问题九、Hibernate里面如何用Criteria 查询记录数

【问题描述】在工作中,有一个比较复杂的feature使用的是hibernate的Criteria实现的查询,但是PM要求在查询数据前,先告知用户有多少条数据,让用户去选择返回多少条记录。
【解决办法】使用Projections.count("property") 或者 Projections.rowCount()

Criteria c = session.createCriteria(User.class);  
c.setProjection(Projections.rowCount());  
int rows=Integer.parseInt(c.uniqueResult().toString());
s.setProjection(null)  

参考:http://blog.csdn.net/virgoboy...

问题十、Hibernate Criteria Join with 3 Tables

Criteria c = session.createCriteria(Dokument.class, "dokument");
c.createAlias("dokument.role", "role"); // inner join by default
c.createAlias("role.contact", "contact");
c.add(Restrictions.eq("contact.lastName", "Test"));
return c.list();

或者这样:

Criteria c = session.createCriteria(Dokument.class);
c.createAlias("role", "role"); // inner join by default
c.createAlias("role.contact", "contact");
c.add(Restrictions.eq("contact.lastName", "Test"));
return c.list();

如果实体对象中含有OneToMany关联对象的情况,既是实体中含有list或Set等关联实体集合的情况下怎么办呢?
这个还不知道怎么办,呵呵
方法其实是非常简单的:

dc.createAlias("tags", "t");          
dc.add(Restrictions.eq("t.id", tagId));  

其中tags是个Set,但是想查找属性tags中含有id为tagId的实体,使用上面的就可以了。

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

DetachedCriteria dc = DetachedCriteria.forClass(Student.class);  
dc.add(Restrictions.like("team.id", teamId, MatchMode.ANYWHERE));  

据我个人的经验,team后只能跟其主键属性,比较其他属性要用别名。

参考:http://stackoverflow.com/ques...
http://www.cnblogs.com/newpan...

问题十一、DetachedCriteria、Criteria 使用区别

在常规的Web编程中,有大量的动态条件查询,即用户在网页上面自由选择某些条件,程序根据用户的选择条件,动态生成SQL语句,进行查询。
此时,我们不能在Web层使用Criteria,因为它是和Session绑定的。
DetachedCriteria可以解决这个问题,即在web层,程序员使用DetachedCriteria来构造查询条件,然后将这个 DetachedCriteria作为方法调用参数传递给业务层对象。而业务层对象获得DetachedCriteria之后,可以在session范围内直接构造Criteria,进行查询。就此,查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦,非常完美!

Criteria 和 DetachedCriteria 的主要区别
在于创建的形式不一样, Criteria 是在线的,所以它是由 Hibernate Session 进行创建的,而 DetachedCriteria 是离线的,创建时无需Session .
DetachedCriteria的创建

DetachedCriteria 提供了 2 个静态方法 ,进行DetachedCriteria 实例的创建。
forClass(Class)
forEntityName(Name)

Spring 的框架提供了对于离线查询的支持,非常的简单的使用那些方法
Spring 的框架提供了getHibernateTemplate().findByCriteria(detachedCriteria) 方法可以很方便地根据DetachedCriteria 来返回查询结果。Criteria的子类就是 DetachedCriteria 我们可以简单的使用就好了。
使用到了这些我们就不得不说 Restrictions 是产生查询条件的工具类。
当然你也可以手动这么干:

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作为子查询

//主查询:人员查询
DetachedCriteria searDc =
DetachedCriteria.forClass(QymlPerson.class);

//子查询:职务人员关系表
DetachedCriteria sub =
DetachedCriteria.forClass(QymlPositionUserLink.class);
sub.add(Restrictions.eq("positionunid", positionunid));
//子查询:指定查询的列(也就是select usernuid from ....)
sub.setProjection(Property.forName("userunid"));

//主查询和子查询关联(也就是where unid in (select userunid from...) )
searDc.add(Property.forName("unid").in(sub));

在上面的例子中,用个一个类似于下面SQL 的子查询

Select * from Person a where a.unid in (select userunid from PositionUserLink b where
b.positionunid = ..)

Property 还有其他的条件判断,参考api
http://docs.jboss.org/hiberna...
ion/Property.html。

动态关联抓取

我们的抓取模式,对于1对多的关联的形式!是不是抓取过来呢?
你可以使用setFetchMode()在运行时定义动态关联抓取的语义

List cats = sess.createCriteria(Cat.class)
    .add( Restrictions.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.JOIN)
    .setFetchMode("kittens", FetchMode.JOIN)
    .list();
    

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

参考:http://blog.csdn.net/u0128819...
http://blog.sina.com.cn/s/blo...

问题十二、投影(Projections)、聚合(aggregation)和分组(grouping)

org.hibernate.criterion.Projections是 Projection 的实例工厂。
我们通过调用setProjection()应用投影到一个查询。这个的意思就是查询哪一列的意思
用来进行聚合操作,和sql中的聚合类似.求和/求平均值/统计记录数/…等等.
还有用来获取获取对象的某些属性(表字段)或属性集合.正常情况下,查询返回的是对象或对象的集合.使用投影的话就可以只返回你需要的属性值.此时,即Hibernate不把记录封装对象了,只返回你在投影中设置的属性的值(值的集合)的数组

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount() )
        //当你添加一个投影到一个投影列表中时 你可以为它指定一个别名:如
        //.add( Projections.rowCount() ,"count")
        .add( Projections.avg("weight") )
        .add( Projections.max("weight") )
        .add( Projections.groupProperty("color") )
    )
    .list();

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

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
    //.setProjection( Projections.groupProperty("color").as("colr") )
    .addOrder( Order.asc("colr") )
    .list();

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

List results = session.createCriteria(Cat.class)
    .setProjection( Projections.projectionList()
        .add( Projections.rowCount().as("catCountByColor") )
        .add( Property.forName("name"))
        .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();

参考:http://blog.csdn.net/u0128819...