文档库 最新最全的文档下载
当前位置:文档库 › DetachedCriteria

DetachedCriteria

Hibernate3的DetachedCriteria支持
2005-07-12 09:55作者:robbin出处:Java视线责任编辑:方舟
Hibernate3支持DetachedCriteria,这是一个非常有意义的特性!我们知道,在常规的Web编程中,有大量的动态条件查询,即用户在网页上面自由选择某些条件,程序根据用户的选择条件,动态生成SQL语句,进行查询。

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

DetachedCriteria可以解决这个问题,即在web层,程序员使用DetachedCriteria来构造查询条件,然后将这个DetachedCriteria作为方法调用参数传递给业务层对象。而业务层对象获得DetachedCriteria之后,可以在session范围内直接构造Criteria,进行查询。就此,查询语句的构造完全被搬离到web层实现,而业务层则只负责完成持久化和查询的封装即可,与查询条件构造完全解耦,非常完美!这恐怕也是以前很多企图在web层代码中构造HQL语句的人想实现的梦想吧!
示例代码片段如下:

web层程序构造查询条件:

java代码:

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

Department和Employee是一对多关联,查询条件为:

名称是“department”开发部门;
createAlias("employees", "e"):创建别名
部门里面的雇员年龄大于20岁;

业务层对象使用该条件执行查询:

java代码:

detachedCriteria.getExecutableCriteria(session).list();

最大的意义在于,业务层代码是固定不变的,所有查询条件的构造都在web层完成,业务层只负责在session内执行之。这样代码就可放之四海而皆准,都无须修改了。

然而Spring和Hibernate3的DetachedCriteria有不兼容的问题,因此在Spring环境下面使用Hibernate3需要注意:

Spring的HibernateTemplate提供了Hibernate的完美封装,即通过匿名类实现回调,来保证Session的自动资源管理和事务的管理。其中核心方法是:


java代码:

HibernateTemplate.execute(new HibernateCallback() {
 public Object doInHibernate(Session session) throws HibernateException {
....
 }
}

回调方法提供了session作为参数,有了session,就可以自由的使用Hibernate API编程了。使用了spring的之后,代码修改如下:

web层代码:

java代码:

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

构造detachedCriteria,作为参数传递给departmentManager

业务层代码使用spring,DepartmentManager的findByCriteria如下:

java代码:

public List findByCriteria(final DetachedCriteria detachedCriteria) {
 return (List) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
return criteria.list();
}
 });
}

实际上也就是:

java代码:

Criteria criteria = detachedCriteria.getExecutableCriteria(session);
return criteria.list();

而已

但是该程序代码执行,会抛出强制类型转换异常!

我跟踪了一下spring和Hibernate源代码,原因如下:

spring的HibernateTemplate的execute方法提供的回调接口具有Session作为参数,但是实际上,默认情况下,HibernateTemplate传递给回调接口的session并不是org.hibernate.impl.SessionImpl类,而是SessionImpl类的一个Proxy类。之所以替换成为一个Proxy类,HibernateTemplate的注释说明,Proxy提供了一些额外的功能,包括自动设置Cachable,Transaction的超时时间,Session资源的更积极的关闭等等。

java代码:

private boolean exposeNativeSession = false;
...

execute方法内部:

Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));

但是遗憾的是,Hibernate的DetachedCriteria的setExecutableCriteria方法却要求将session参数强制转为SessionImpl,但是spring传过来的却是一个Proxy类,因此就报错了。

java代码:

public Criteria getExecutableCriteria(Session session) {
 impl.setSession( (SessionImpl) session ); // 要求SessionImpl,Spring传递的是Proxy
 return impl;
}

解决方法,禁止Spring的HibernateTemplate传递Proxy类,强制要求它传递真实的SessionImpl类,即给exexute方法增加一个参数,提供参数为true,如下:

java代码:

public List findByCriteria(final DetachedCriteria detachedCriteria) {
 return (List) getHibernateTemplate().execute(new HibernateCallback() {
pu

blic Object doInHibernate(Session session) throws HibernateException {
Criteria criteria = detachedCriteria.getExecutableCriteria(session);
return criteria.list();
}
 }, true);
}


1: QBE (Query By Example)
Criteria cri = session.createCriteria(Student.class);
cri.add(Example.create(s)); //s是一个 Student 对象
list cri.list();
实质:创建一个模版,比如我有一个表serial 有一个 giftortoy 字段,我设置 serial.setgifttoy("2"),
则这个表中的所有的giftortoy 为 2 的数据都会出来
QBC查询方式

QBC(Query By Criteria)查询方式是 Hibernate 提供的 “ 更加面向对象 ” 的一种检索方式。 QBC 在条件查询上比 HQL 查询更为灵活,而且支持运行时动态生成查询语句。
在Hibernate 应用中使用 QBC 查询通常经过 3 个步骤
(1)使用 Session 实例的 createCriteria() 方法创建 Criteria 对象
(2)使用工具类 Restrictions 的相关方法为 Criteria 对象设置查询对象
(3)使用 Criteria 对象的 list() 方法执行查询,返回查询结果
Restrictions类的常用方法
Restrictions.eq(String propertyName,Object value)
等于
Restrictions.allEq(Map propertyNameValues)
使用Map key/value 进行多个等于的比对
Restrictions.gt(String propertyName, Object value)
大于 > (gt----->greater than)
Restrictions.ge(String propertyName, Object value)
大于等于 >= (ge----->greater equal)
Restrictions.It(String propertyName, Object value)
小于< (It---->less than)
Restrictions.Le(String propertyName, Object value)
小于等于<= (le---->less equal)
Restrictions.between(String propertyName, Object lo, Object hi)
对应SQL 语句的 Between 子句
Restrictions.like(String propertyName, Object value)
对应SQL 语句的 LIKE 子句
Restrictions.in(String propertyName, Collection value)
对应SQL 语句的 in 子句
Restrictions.and(Criterion lhs, Criterion rhs)
And关系
Restrictions.or(Criterion lhs, Criterion rhs)
Or关系
Restrictions.sqlRestriction(String sql,Object[] values,Type[] types)
SQL限定查询

工具类Order 提供设置排序方式
Order.asc(String propertyName)
升序排序
Order.desc(String propertyName)
降序排序

工具类Projections 提供对查询结果进行统计与分组操作
Porjections.avg(String propertyName)
求某属性的平均值
Projections.count(String propertyName)
统计某属性的数量
Projections.countDistinct(String propertyName)
统计某属性的不同值的数量
Projections.groupProperty(String propertyName)
指定一组属性值
Projections.max(String propertyName)
某属性的最大值
Projections.min(String propertyName)
某属性的最小值
Projections.projectionList()
创建一个新的projectionList 对象
Projections.rowCount()
查询结果集中记录的条数
Projections.sum(String propertyName)
返回某属性值的合计

QBE查询

QBE查询就是检索与指定样本对象具有相同属性值

的对象。因此 QBE 查询的关键就是样本对象的创建,样本对象中的所有非空属性均将作为查询条件。 QBE 查询的功能子集,虽然 QBE 没有 QBC 功能大,但是有些场合 QBE 使用起来更为方便。

工具类Example 为 Criteria 对象指定样本对象作为查询条件
Java代码
1 Session session = HibernateSessionFactory.getSessionFactory().openSession();
2 Transaction ts = session.beginTransaction();
3 Customer c = new Customer();
4 c.setCname("Hibernate");
5 Criteria criteria = session.createCriteria(Customer. class );
6 Criteria.add(Example.create(c));
7 Iterator it = criteria.list().iterator();
8 https://www.wendangku.net/doc/ac10292568.html,mit();
9 HibernateSessionFactory.closeSession();


QBC分页查询

Criteria为我们提供了两个有用的方法: setFirstResult(int firstResult) 和 setMaxResults(int maxResults).
setFirstResult(int firstResult)方法用于指定从哪一个对象开始检索(序号从 0 开始),默认为第一个对象(序号为 0 ); setMaxResults(int maxResults) 方法用于指定一次最多检索出的对象数目,默认为所有对象。
Java代码
1 Session session = HibernateSessionFactory.getSessionFactory().openSession();
2 Transaction ts = null ;
3 Criteria criteria = session.createCriteria(Order. class );
4 int pageSize = 15;
5 int pageNo = 1;
6 criteria.setFirstResult((pageNo-1)*pageSize);
7 criteria.setMaxResults(pageSize);
8 Iterator it = criteria.list().iterator();
9 https://www.wendangku.net/doc/ac10292568.html,mit();
10 HibernateSessionFactory.closeSession();

QBC复合查询
复合查询就是在原有的查询基础上再进行查询。例如在顾客对定单的一对多关系中,在查询出所有的顾客对象后,希望在查询定单中money 大于 1000 的定单对象
DetachedCriteria criteria= DetachedCriteria . forClass (Model. class );
criteria.add(Restrictions. eq ( "userid" , userid));
criteria.add(Restrictions. eq ( "state" , false ));
criteria.add(Restrictions. not ( Expression . eq ( "freeze" , false ) ));
criteria.addOrder( Order. desc ( "createtime" ) );
return modelDAO .findByCriteria(criteria);
Java代码
1 Session session = HibernateSessionFactory.getSessionFactory().openSession();
2 Transaction ts = session.beginTransaction();
3 Criteria cuscriteria = session.createCriteria(Customer. class );
4 Criteria ordCriteria = cusCriteria.createCriteria("orders");
5 ordCriteria.add(Restrictions.gt("money", new Double(1000)));
6 Iterator it = cusCriteria.list().iterator();
7 https://www.wendangku.net/doc/ac10292568.html,mit();
8 HibernateSessionFactory.closeSession();
QBC离线查询
离线查询又叫DetachedCriteria 查询,它可以在 Session 之外进行构造,只有在需要执行查询时才与 Session 绑定。
2: QBC (Query By Criteria) 主要有 Criteria,Criterion,Oder,Restrictions 类组成
session = this.getSession();
Criteria cri = session.createCriteria(JdItemSerialnumber.class);
Criterion cron = Restrictions.like("customer",name);
cri.add(cron);
list = cri.list();
==

============================
比较运算符
HQL运算符 QBC 运算符 含义
= Restrictions.eq() 等于
<> Restrictions.not(Exprission.eq()) 不等于
> Restrictions.gt() 大于
>= Restrictions.ge() 大于等于
< Restrictions.lt() 小于 [Page]
<= Restrictions.le() 小于等于
is null Restrictions.isnull() 等于空值
is not null Restrictions.isNotNull() 非空值
like Restrictions.like() 字符串模式匹配
and Restrictions.and() 逻辑与
and Restrictions.conjunction() 逻辑与
or Restrictions.or() 逻辑或
or Restrictions.disjunction() 逻辑或
not Restrictions.not() 逻辑非
in(列表 ) Restrictions.in() 等于列表中的某一个值 [Page]
ont in(列表 ) Restrictions.not(Restrictions.in()) 不等于列表中任意一个值
between x and y Restrictions.between() 闭区间 xy 中的任意值
not between x and y Restrictions.not(Restrictions..between()) 小于值 X 或者大于值 y
3: HQL
String hql = "select https://www.wendangku.net/doc/ac10292568.html, ,avg(s.age) from Student s group by https://www.wendangku.net/doc/ac10292568.html,";
Query query = session.createQuery(hql);
list = query.list();
....
4: 本地 SQL 查询
session = sessionFactory.openSession();
tran = session.beginTransaction();
SQLQuery sq = session.createSQLQuery(sql);
sq.addEntity(Student.class);
list = sq.list();
https://www.wendangku.net/doc/ac10292568.html,mit();
5: QID
Session的 get() 和 load() 方法提供了根据对象 ID 来检索对象的方式。该方式被用于事先知道了要检索对象 ID 的情况。
Hibernate: HQL/QBC 查询语言比较的用法
Hib的检索方式 1 、导航对象图检索方式。通过已经加载的对象,调用 .iterator() 方法可以得到 order 对象如果是首次执行此方法, Hib 会从数据库加载关联的 order 对象,否则就从缓存中得到。 2 、 OID 检索方式。通过 session 的 get , load 方法知道了 OID 的情况下可以使用 3 、 HQL 检索方

Hib的检索方式
1、导航对象图检索方式。通过已经加载的对象,调用 .iterator() 方法可以得到 order 对象如果是首次执行此方法, Hib 会从数据库加载关联的 order 对象,否则就从缓存中得到。
2、 OID 检索方式。通过 session 的 get , load 方法知道了 OID 的情况下可以使用
3、 HQL 检索方式。使用面向对象的 HQL 查询语句 session 的 find 方法利用 HQL 来查询
4、 QBC 检索方式。利用 QBCAPI 来检索它是封装了基于字符串的查询语句
5、本地的 SQL 检索方式。使用本地数据库的 SQL 查询语句 Hib 会负责把检索到的 JDBC 结果集映射为持久化对象图。
五种检索方式的使用场合和特点:
HQL : 是面向对象的查询语言,同 SQL 有些相似是 Hib 中最常用的方式。
查询设定各种查询条件。
支持投影查询,检索出对象的部分属性。
支持分页查询,允许使用having 和 group by
提供内制的聚集函数,sum() , min() , max()
能调用用户的自定义SQL
支持子查询,嵌入式查询
支持动

态绑定参数
建议使用Query 接口替换 session 的 find 方法。

Query Q = session.createQuery("from customer as c where https://www.wendangku.net/doc/ac10292568.html, = :customerName" +"and c.age = :customerAge");
query.setString("customerName" , "tom");
query.setInteger("customerAge" , "21");
list result = query.list();
QBC : QBCAPI提供了另一种方式,主要是 Criteria 接口、 Criterion 接口和 Expression 类
Criteria criteria = session.createCriteria(customer.class);
Criterion criterion1 =Expression.like("name","t%");
Criterion criterion2 =Expression.eq("age",new Integer(21));
Critera = criteria.add(criterion1) ;
Critera = criteria.add(criterion2) ;
list result = criteria.list();
或是: list result = session.createCriteria(Customer.class).add(Expression.eq("https://www.wendangku.net/doc/ac10292568.html,","tom")).list();
SQL : 采用 HQL 和 QBC 检索时, Hib 生成 SQL 语句适用所有数据库。
Query query =session.createSQLQuery("select {c.*} from customers c where https://www.wendangku.net/doc/ac10292568.html, like : customername " + "and c.age =:customerage","c",customer.calss);
query.setString("customername","tom");
query.setInteger("customerage","21");
list result = query.list();
/////////////多态查询
HQL : session.createQuery("from employee");
QBC : session.createCriteria(employee.class);
HQL : session.createQuery("from hourlyEmployee");
QBC : session.createCriteria(hourlyEmployee.class);
下面的HQL 查询语句将检索出所有的持久化对象:
from https://www.wendangku.net/doc/ac10292568.html,ng.Object ;
from java.io.serializable ;
////////////查询的排序
1、查询结果按照客户姓名升序排列:
HQL :
Query query = session.createQuery
("from customer c order by https://www.wendangku.net/doc/ac10292568.html,");
QBC :
Criteria criteria = session.createCriteria(customer.class);
criteria.addOrder(order.asc("name"));
HQL :
Query query = session.createQuery("from customer c orderby https://www.wendangku.net/doc/ac10292568.html, asc , c.age desc");
QBC :
Criteria criteria =session.createCriteria(customer.class);
criteria.addOrder(order.asc ("name"));
criteria.addOrder(order.desc("age"));
import net.sf.hibernate.pression.Order
import mypack.Order
...........
Criteria criteria = session.createCritria (mypack.Order.class);
criteria.addOrder(net.sf.hibernate.Order.asc("name"));
///////////HQL语句的参数绑定 Query 接口
提供了绑定各种Hib 映射类型的方法。
setBinary()
setString()
setBoolean()
setByte()
setCalendar()
setCharacter()
setDate()
setDouble()
setText()
setTime()
setTimestamp()
setEntity()
//把参数与一个持久化类的事例绑定
lsit result = session.createQuery
("from order o where o.customer = :customer").setEntity("customer" , customer).list ;
setParameter()
//绑定任意类型的参数
setProperties()
//把命名参数与一个对象的属性值绑定
Query query = session.createQuery
("from customer c where https://www.wendangku.net/doc/ac10292568.html, =:name " + "and c.age =:age" );
Query.setProperties(customer);
Java代码
public AlBasic queryAlBasicByEtpsIdAndAnnlYear(String entityName, String etpsId, String annlYear) {
if (etpsId == n

ull || "".equals(etpsId) || annlYear == null || "".equals(annlYear))
return null;
DetachedCriteria dc = DetachedCriteria.forEntityName(entityName);
dc.add(Restrictions.eq("etpsId", etpsId));
dc.add(Restrictions.eq("annlYear", annlYear));
List result = findByCriteria(dc);
if (result == null || result.size() == 0) {
return null;
}
return (AlBasic) result.get(0);
}

相关文档