使用Hibernate Criteria完成灵活的组合查询
来源:互联网 发布:魔百和网络机顶盒 编辑:程序博客网 时间:2024/05/20 03:08
使用Hibernate Criteria完成灵活的组合查询
在Hibernate中,进行查询主要提供了两个核心API:Query以及Criteria,前者是针对HQL语句的,就是说是面向结构化语句的查询,而后者是面向对象(非常适合没有SQL基础的程序开发人员使用)。
怎样生成Criteria?
生成criteria需要借助Hibernate的Session#createCriteria(Class
select * from `t_user` where `username`='张三';
其中查询原子语句可以认为是username
=’张三’,Criteria的出发也是这样子的,它主要为你提供生成查询原子语句的方法,以及语句之间的逻辑组合,还有就是最常用的排序。我们想要的,基本而简单的,Criteria都提供给我们了。
Criteria提供了#add方法为我们添加Criteria专用表达式Criterion。
现在需要了解下,怎样生成Criterion表达式。Hibernate3之后为我们提供的API是Restrictions实现类,该类为我们提供了静态方法来生成查询原子语句生成方法#eq、#ne、#gt、#lt、#ge、#le、#in、#like等等
方法接受的参数虽然说都不一样,但是也是极其相似的,就是String property(属性的名称) ,返回值都是Criterion。
比如上述的username
=’张三’,可以使用Restrictions生成的Criterion查询表达式是Restrictions.eq(“username”, “张三”):Criterion。这里的“username”是你的领域模型中的属性名称,而不是数据库的列名称。
Criteria中的方法
Criteria#add(Criterion c)以及Criteria#addOrder(Order order)是Criteria中核心的两个方法。一个用于添加Criterion表达式,另外一个用于添加排序。
介绍完了Criteria、Criterion、Restrictions,下面讲讲项目开发中常见的组合查询实现问题。
组合查询作为一个应用程序的基本功能,具有灵活多变的需求,现在的三层开发模式下,可能会在Dao对应的DaoImpl(Dao实现中,一般Dao作为接口,定义实现需要的方法),手工写入具体的hql语句来实现,如果在类不多的前提下(一般来说,一个类对应一个DaoImpl),这样写还算比较简单, 虽说实现简单,却不见的灵活。比方说客户今天说,按照用户名查询用户、明天又改变需求了,需要添加部门来查询用户,如果你是手工写入具体hql的,那么,你就不得不去更改DaoImpl中的hql语句了,如果你设计得比较好的话,或许不需要改变入参(这是最理想的情况了),但是WEB层的参数更改是或许是需要的,这样算算,就改动了持久化层与WEB层。那么怎样不需要代码,就能满足任意的组合查询呢?(仔细想想,这样做,开发量是减少了,如果不约束查询串,那么会有安全性问题)。
在这里我提供一种思路:前台无论传递多少参数,都需要经过HttpServletRequest对象,所有,只要使用这个对象,你就可以取得任意的参数串。而Dao层,要保证Criteria能自由地组合参数(这句话肯定是很抽象的),你可以在Dao中,使用命令行设计模式,结合组合查询的方法combineQuery(Set commands)来进行实现,commands一般就包含了子查询和排序两种命令在里面,在方法内部通过add(Criterion)以及addOrder(Order)来将属性以及排序拼接。看看以下的代码:
命令行接口:
package com.test;import org.hibernate.Criteria;/** * @author daniel * */public interface CriteriaCommand { public Criteria execute(Criteria c);}
域命令行实现类:
/** * */package com.test;import java.util.List;import java.util.Set;import org.apache.commons.lang.builder.EqualsBuilder;import org.apache.commons.lang.builder.HashCodeBuilder;import org.hibernate.Criteria;import org.hibernate.criterion.MatchMode;import org.hibernate.criterion.Restrictions;/** * @author daniel * */public class FieldCommandImpl implements CriteriaCommand { public static enum OperationMode { EQ, NE, GT, LT, GE, LE, IN, LIKE } //属性名称 private String propertyName; //属性值 private Object propertyValue; //操作 private OperationMode operation; public FieldCommandImpl() { this(null, null, OperationMode.EQ); } public FieldCommandImpl(String propertyName, Object propertyValue, OperationMode mode) { this.propertyName = propertyName; this.propertyValue = propertyValue; this.operation = mode; } /** * @return the propertyName */ public Object getPropertyName() { return propertyName; } /** * @param propertyName the propertyName to set */ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } /** * @return the propertyValue */ public Object getPropertyValue() { return propertyValue; } /** * @param propertyValue the propertyValue to set */ public void setPropertyValue(Object propertyValue) { this.propertyValue = propertyValue; } /** * @return the operation */ public OperationMode getOperation() { return operation; } /** * @param operation the operation to set */ public void setOperation(OperationMode operation) { this.operation = operation; } @SuppressWarnings("unchecked") public Criteria execute(Criteria c) { // TODO Auto-generated method stub if(c == null) { throw new NullPointerException(); } else { if(OperationMode.EQ.equals(operation))//等于 { c.add(Restrictions.eq(propertyName, propertyValue)); } else if(OperationMode.NE.equals(operation))//不等于 { c.add(Restrictions.ne(propertyName, propertyValue)); } else if(OperationMode.GT.equals(operation))//大于 { c.add(Restrictions.gt(propertyName, propertyValue)); } else if(OperationMode.GE.equals(operation))//大于等于 { c.add(Restrictions.ge(propertyName, propertyValue)); } else if(OperationMode.LT.equals(operation))//小于 { c.add(Restrictions.lt(propertyName, propertyValue)); } else if(OperationMode.LE.equals(operation))//小于等于 { c.add(Restrictions.le(propertyName, propertyValue)); } else if(OperationMode.IN.equals(operation))//in操作 { if(propertyValue instanceof List) { List<Object> in_params = (List<Object>) propertyValue; c.add(Restrictions.in(propertyName, in_params)); } else if(propertyValue instanceof Set) { Set<Object> in_params = (Set<Object>) propertyValue; c.add(Restrictions.in(propertyName, in_params)); } else if(propertyValue instanceof Object[]) { Object[] in_params = (Object[]) propertyValue; c.add(Restrictions.in(propertyName, in_params)); } else { throw new IllegalArgumentException();//其他,非法参数 } } else if(OperationMode.LIKE.equals(operation)) { c.add(Restrictions.like(propertyName, (String) propertyValue, MatchMode.ANYWHERE));//%a%的匹配模式 } } return c; } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // TODO Auto-generated method stub HashCodeBuilder builder = new HashCodeBuilder(); builder.append(propertyName); builder.append(propertyValue); builder.append(operation); return builder.toHashCode(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if(obj == null) { return false; } if(obj == this) { return true; } if(!obj.getClass().equals(this.getClass())) { return false; } FieldCommandImpl command = (FieldCommandImpl) obj; EqualsBuilder builder = new EqualsBuilder(); builder.append(propertyName, command.getPropertyName()); builder.append(propertyValue, command.getPropertyValue()); builder.append(operation, command.getOperation()); return builder.isEquals(); }}
排序命令行实现类:
/** * */package com.test;import org.apache.commons.lang.builder.EqualsBuilder;import org.apache.commons.lang.builder.HashCodeBuilder;import org.hibernate.Criteria;import org.hibernate.criterion.Order;/** * @author daniel * */public class SortCommandImpl implements CriteriaCommand { public static enum SortMode { ASC, DESC } private String propertyName; private SortMode sortMode; public SortCommandImpl() { this(null, SortMode.ASC);//默认增序排序 } public SortCommandImpl(String propertyName, SortMode sortMode) { this.propertyName = propertyName; this.sortMode = sortMode; } /** * @return the propertyName */ public String getPropertyName() { return propertyName; } /** * @param propertyName the propertyName to set */ public void setPropertyName(String propertyName) { this.propertyName = propertyName; } /** * @return the sortMode */ public SortMode getSortMode() { return sortMode; } /** * @param sortMode the sortMode to set */ public void setSortMode(SortMode sortMode) { this.sortMode = sortMode; } public Criteria execute(Criteria c) { // TODO Auto-generated method stub if(c == null) { throw new NullPointerException(); } else { if(SortMode.ASC.equals(sortMode))//升序 { c.addOrder(Order.asc(propertyName)); } else if(SortMode.DESC.equals(sortMode))//降序 { c.addOrder(Order.desc(propertyName)); } else { throw new IllegalArgumentException(); } return c; } } /* (non-Javadoc) * @see java.lang.Object#hashCode() */ @Override public int hashCode() { // TODO Auto-generated method stub HashCodeBuilder builder = new HashCodeBuilder(); builder.append(propertyName); builder.append(sortMode); return builder.toHashCode(); } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { // TODO Auto-generated method stub if(obj == null) { return false; } if(obj == this) { return true; } if(!obj.getClass().equals(this.getClass())) { return false; } SortCommandImpl command = (SortCommandImpl) obj; EqualsBuilder builder = new EqualsBuilder(); builder.append(propertyName, command.getPropertyName()); builder.append(sortMode, command.getSortMode()); return builder.isEquals(); }}
为什么会有命令行接口?其实就是为了方法参数更加优雅。
为什么要区分域命令行以及排序命令行?
其实是针对add(Criterion)以及addOrder(Order order)两个方法的调用。
在生成子查询时,Criterion需要的信息主要是属性名称、属性值以及操作类型,这样才能决定生成什么样的Criterion。比方说,传递进来的FieldCommandImpl中propertyName=username、而propertyValue=张三,mode=OperationMode.EQ,就可以决定生成一个Restrictions.eq(propertyName,propertyValue)的Criterion表达式。
在生成排序时,需要调用生成对应的Order对项,而Order#asc(String propertyName):Order以及Order.desc#desc(String propertyName):Order。毕竟排序时需要的信息比生成原子查询Criterion表达式i信息少,只需要知道属性名称和排序方式就够了。
Dao层的实现方法:
/** * 适用于组合查询 */ public List<E> zuheQuery(final Class<?> entityClass, final Set<CriteriaCommand> commands) { return template.execute(new HibernateCallback<List<E>>() { public List<E> doInHibernate(Session arg0) throws HibernateException, SQLException { // TODO Auto-generated method stub Criteria criteria = arg0.createCriteria(entityClass); //使用两个循环完成 了查询子句和排序子句的拼接 if(commands != null && !commands.isEmpty()) { for(CriteriaCommand command : commands) { command.execute(criteria); } } return criteria.list(); } });
只要Service层对Web层暴露API,就可以在Web层使用了。上面说过,如果保证Web传递的参数无差异化(也就是说传递过来多少个参数,都没有关系,能够自动将参数解析,并且保证一个不少地传递给Service层),那有一个核心的对象就是request了,可以使用它作为参数,当然,request获取到的参数太原始,需要我们进行处理,所以,可以创建一个QueryFilter类,来封装request并且对request参数进行处理。时间有限,今天就先写到这里。
- 使用Hibernate Criteria完成灵活的组合查询
- Hibernate.Criteria完成多件条组合分页查询
- Hibernate查询—利用Criteria完成表的查询操作
- Hibernate中Criteria的使用(条件查询)
- Hibernate的Criteria查询
- Hibernate Criteria 组合查询条件
- 灵活使用Hibernate的查询对象DetachedCriteria
- 灵活使用Hibernate的查询对象DetachedCriteria
- 灵活使用Hibernate的查询对象DetachedCriteria
- Hibernate使用Criteria实现查询
- 加强hibernate的criteria查询中的使用Example查询的
- hibernate criteria的使用
- hibernate Criteria 的使用
- Hibernate Criteria的嵌套查询
- hibernate的Criteria作连表查询
- Hibernate的Criteria查询总结
- 关于Hibernate的Criteria查询
- 了解hibernate的Criteria查询
- 第六周项目六--复数模板类(友元函数)
- 零基础入门学习C 001
- html5 websocket 无法建立到服务器的连接 一种解决方法
- thinking in java第七天
- Go语言defer的使用
- 使用Hibernate Criteria完成灵活的组合查询
- 电视节目
- iOS开发-字符串和数组NSString NSArray的操作
- sqlite入门基础(一):sqlite3_open,sqlite3_exec,slite3_close
- Caused by: java.lang.UnsatisfiedLinkError
- [后缀数组+贪心] poj 3518 Sequence
- 【算法之链表(二)】判断两个链表是否相交并找出交点
- MyISAM 和 InnoDB 区别
- 多重背包——POJ 1276