最近在项目中使用 Spring 和 Hibernate 进行开发
有感于 Criteria 比较好用
在查询思路方法设计上可以灵活
根据 Criteria
特点来方便地进行查询条件
组装
现在对 Hibernate
Criteria
使用方法进行整理总结:
Hibernate 设计了 CriteriaSpec
ication 作为 Criteria
父接口
下面提供了 Criteria和DetachedCriteria
Criteria 和 DetachedCriteria
主要区别在于创建
形式不
样
Criteria 是在线
所以它是由 Hibernate Session 进行创建
;而 DetachedCriteria 是离线
创建时无需Session
DetachedCriteria 提供了 2 个静态思路方法 forClass(Class) 或 forEntityName(Name) 进行DetachedCriteria 例子
创建
Spring
框架提供了getHibernateTemplate
.findByCriteria(detachedCriteria) 思路方法可以很方便地根据DetachedCriteria 来返回查询结果
Criteria 和 DetachedCriteria 均可使用 Criterion 和 Projection 设置查询条件
可以设置 FetchMode( 联合查询抓取
模式 )
设置排序方式
对于 Criteria 还可以设置 FlushModel(冲刷 Session
方式)和 LockMode (数据库锁模式)
下面对 Criterion 和 Projection 进行详细介绍说明
Criterion 是 Criteria
查询条件
Criteria 提供了 add(Criterion criterion) 思路方法来添加查询条件
Criterion 接口
主要实现包括: Example 、 Junction 和 SimpleExpression
而 Junction
实际使用是它
两个子类 conjunction 和 disjunction
分别是使用 AND 和 OR 操作符进行来联结查询条件集合
Criterion
例子可以通过 Restrictions 工具类来创建
Restrictions 提供了大量
静态思路方法
如 eq (等于)、 ge (大于等于)、 between 等来思路方法
创建 Criterion 查询条件 (SimpleExpression 例子)
除此的外
Restrictions 还提供了思路方法来创建 conjunction 和 disjunction 例子
通过往该例子
add(Criteria) 思路方法来增加查询条件形成
个查询条件集合
至于 Example
创建有所区别
Example 本身提供了
个静态思路方法 create(Object entity)
即根据
个对象(实际使用中
般是映射到数据库
对象)来创建
然后可以设置
些过滤条件:
Example exampleUser =Example.create(u)
.ignoreCase
// 忽略大小写
.enableLike(MatchMode.ANYWHERE);
// 对 String 类型
属性
无论在那里值在那里都匹配
相当于 %value% Project 主要是让 Criteria 能够进行报表查询
并可以实现分组
Project 主要有 SimpleProjection 、ProjectionList 和 Property 3个实现
其中SimpleProjection 和 ProjectionList
例子化是由内建
Projections 来完成
如提供
avg 、 count 、 max 、 min 、 sum 可以让开发者很容易对某个字段进行统计查询
Property 是对某个字段进行查询条件
设置
如通过Porperty.forName(“color”).in(
String
{“black”,”red”,”write”}); 则可以创建
个 Project 例子
通过 criteria
add(Project) 思路方法加入到查询条件中去
使用 Criteria 进行查询
主要要清晰
是 Hibernate 提供了那些类和思路方法来满足开发中查询条件
创建和组装
下面介绍几种使用方法:
1. 创建
个Criteria 例子
org.hibernate.Criteria接口表示特定持久类
个查询
Session是 Criteria例子
工厂
Criteria crit = sess.createCriteria(Cat.);
crit.MaxResults(50);
List cats = crit.list;
2. 限制结果集内容
个单独
查询条件是org.hibernate.criterion.Criterion 接口
个例子
org.hibernate.criterion.Restrictions类 定义了获得某些内置Criterion类型
工厂思路方法
List cats = sess.createCriteria(Cat.)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.between("weight", minWeight, maxWeight) )
.list;
约束可以按逻辑分组
List cats = sess.createCriteria(Cat.)
.add( Restrictions.like("name", "Fritz%") )
.add( Restrictions.or(
Restrictions.eq( "age", Integer(0) ),
Restrictions.isNull("age")
) )
.list;
List cats = sess.createCriteria(Cat.)
.add( Restrictions.in( "name", String { "Fritz", "Izi", "Pk" } ) )
.add( Restrictions.disjunction
.add( Restrictions.isNull("age") )
.add( Restrictions.eq("age", Integer(0) ) )
.add( Restrictions.eq("age", Integer(1) ) )
.add( Restrictions.eq("age", Integer(2) ) )
) )
.list;
Hibernate提供了相当多
内置criterion类型(Restrictions 子类), 但是尤其有用
是可以允许你直接使用SQL
List cats = sess.createCriteria(Cat.)
.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.)
.add( Restrictions.disjunction
.add( age.isNull )
.add( age.eq( Integer(0) ) )
.add( age.eq( Integer(1) ) )
.add( age.eq( Integer(2) ) )
) )
.add( Property.forName("name").in( String { "Fritz", "Izi", "Pk" } ) )
.list;
3. 结果集排序
你可以使用org.hibernate.criterion.Order来为查询结果排序
List cats = sess.createCriteria(Cat.)
.add( Restrictions.like("name", "F%")
.addOrder( Order.asc("name") )
.addOrder( Order.desc("age") )
.MaxResults(50)
.list;
List cats = sess.createCriteria(Cat.)
.add( Property.forName("name").like("F%") )
.addOrder( Property.forName("name").asc )
.addOrder( Property.forName("age").desc )
.MaxResults(50)
.list;
4. 关联
你可以使用createCriteria
非常容易
在互相关联
实体间建立 约束
List cats = sess.createCriteria(Cat.)
.add( Restrictions.like("name", "F%")
.createCriteria("kittens")
.add( Restrictions.like("name", "F%")
.list;
注意第 2个 createCriteria
返回
个新
Criteria例子
该例子引用kittens 集合中
元素
接下来
替换形态在某些情况下也是很有用
List cats = sess.createCriteria(Cat.)
.createAlias("kittens", "kt")
.createAlias("mate", "mt")
.add( Restrictions.eqProperty("kt.name", "mt.name") )
.list;
(createAlias
并不创建
个新
Criteria例子
)
Cat例子所保存
的前两次查询所返回
kittens集合是 没有被条件预过滤
如果你希望只获得符合条件
kittens
你必须使用
Maps
List cats = sess.createCriteria(Cat.)
.createCriteria("kittens", "kt")
.add( Restrictions.eq("name", "F%") )
.Maps
.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. 动态关联抓取
你可以使用
FetchMode
在运行时定义动态关联抓取
语义
List cats = sess.createCriteria(Cat.)
.add( Restrictions.like("name", "Fritz%") )
.FetchMode("mate", FetchMode.EAGER)
.FetchMode("kittens", FetchMode.EAGER)
.list;
这个查询可以通过外连接抓取mate和kittens
6. 查询举例
org.hibernate.criterion.Example类允许你通过
个给定例子 构建
个条件查询
Cat cat = Cat;
cat.Sex('F');
cat.Color(Color.BLACK);
List results = session.createCriteria(Cat.)
.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 insensitive comparisons
.enableLike; //use like for comparisons
List results = session.createCriteria(Cat.)
.add(example)
.list;
甚至可以使用examples在关联对象上放置条件
List results = session.createCriteria(Cat.)
.add( Example.create(cat) )
.createCriteria("mate")
.add( Example.create( cat.getMate ) )
.list;
7. 投影(Projections)、聚合(aggregation)和分组(grouping)
org.hibernate.criterion.Projections是 Projection
例子工厂
我们通过
Projection
应用投影到
个查询
List results = session.createCriteria(Cat.)
.Projection( Projections.rowCount )
.add( Restrictions.eq("color", Color.BLACK) )
.list;
List results = session.createCriteria(Cat.)
.Projection( 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.)
.Projection( Projections.alias( Projections.groupProperty("color"), "colr" ) )
.addOrder( Order.asc("colr") )
.list;
List results = session.createCriteria(Cat.)
.Projection( Projections.groupProperty("color").as("colr") )
.addOrder( Order.asc("colr") )
.list;
alias
和as
思路方法简便
将
个投影例子包装到另外
个 别名
Projection例子中
简而言的
当你添加
个投影到
个投影列表中时 你可以为它指定
个别名:
List results = session.createCriteria(Cat.)
.Projection( 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., "cat")
.createAlias("kittens", "kit")
.Projection( 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.)
.Projection( Property.forName("name") )
.add( Property.forName("color").eq(Color.BLACK) )
.list;
List results = session.createCriteria(Cat.)
.Projection( 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.)
.add( Property.forName("sex").eq('F') );
//创建个Session
Session session = .;
Transaction txn = session.beginTransaction;
List results = query.getExecutableCriteria(session).MaxResults(100).list;
txn.commit;
session.close;
DetachedCriteria也可以用以表示子查询
条件例子包含子查询可以通过 Subqueries或者Property获得
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.)
.Projection( Property.forName("weight").avg );
session.createCriteria(Cat.)
.add( Property.forName("weight).gt(avgWeight) )
.list;
DetachedCriteria weights = DetachedCriteria.forClass(Cat.)
.Projection( Property.forName("weight") );
session.createCriteria(Cat.)
.add( Subqueries.geAll("weight", weights) )
.list;
相互关联
子查询也是有可能
:
DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat., "cat2")
.Projection( Property.forName("weight").avg )
.add( Property.forName("cat2.sex").eqProperty("cat.sex") );
session.createCriteria(Cat., "cat")
.add( Property.forName("weight).gt(avgWeightForSex) )
.list;