您的位置:首页 > 数据库 > MySQL

基于Hibernate的动态查询(HQL、Criteria、DetachedCriteria、MySQL)

2016-03-11 11:46 971 查看

概述

动态查询是指系统根据前端传递的参数,自动生成SQL、HQL进行数据查询。现在我用得比较多的是Spring Data 的动态查询,然而前段时间帮人

维护一个比较久远的项目,该项目用Hibernate作为ORM,为了方便我想在Hibernate上实现动态查询。网上搜索了很久,别人贴出的代码要么是

不完整的要么是动能缺失。于是在网上代码的基础上,我进行了调整。途中遇到了几个坑,后来都一一填上。

注:这里给出的代码都是demo级别的,不建议直接用到实际项目中。

项目预览

文件结构

先看看项目文件结构



其中动态查询语句的构造在
DynamicQuery.java
实现。

测试数据



上面的数据是我随机生成的,sql文件已经导出到项目根目录的
test_sfz.sql


功能实现

先看看核心代码

/**
* 返回的是 DetachedCriteria (无需Session的离线Criteria)
* @param clzss
* @param map
* @return
*/
public static DetachedCriteria build(Class clzss, Map<String,Object> map){
final DetachedCriteria dc = DetachedCriteria.forClass(clzss);
Map<String,String> fieldM = buildOrCreateFieldMap(clzss);

if(map.size()>0){
for(Iterator<String> keys = map.keySet().iterator(); keys.hasNext();){
String k=keys.next();
Object v=map.get(k);
if(v == null || v.toString().trim().length()==0)
continue;

String t[] = k.split("_");
if(t.length<2)
continue;

//进行类型转换
String fieldType=fieldM.get(t[1]);
if("class java.lang.String".equals(fieldType))
try{v = (String)v;}catch (Exception e){}
else if("int".equals(fieldType) || "class java.lang.Integer".equals(fieldType))
try{v = Integer.valueOf((String)v);}catch (Exception e){}
else if("long".equals(fieldType) || "class java.lang.Long".equals(fieldType))
try{v = Long.valueOf((String)v);}catch (Exception e){}
else if("float".equals(fieldType) || "class java.lang.Float".equals(fieldType))
try{v = Float.valueOf((String)v);}catch (Exception e){}
else if("double".equals(fieldType) || "class java.lang.Bouble".equals(fieldType))
try{v = Double.valueOf((String)v);}catch (Exception e){}
else if("class java.util.Date".equals(fieldType)){
try {
v = DateUtils.parseDate((String)v, parsePatterns);
}catch (Exception e){}
}

t[0]=t[0].toUpperCase();
if(t[0].equals("LIKE")){
String like=(String)v;
//如果不是以%开头或者结尾,就给前后都加上%
if(!(like.startsWith("%")||like.endsWith("%")))
like="%"+like+"%";
if(t.length==2) dc.add(Restrictions.like(t[1], like));
else{
Disjunction dis=Restrictions.disjunction();
for(int i=1;i<t.length;i++){
dis.add(Restrictions.like(t[i], like, MatchMode.ANYWHERE));
}
dc.add(dis);
}
}else if(t[0].equals("EQ"))
dc.add(Restrictions.eq(t[1],v));
else if(t[0].equals("IN"))
dc.add(Restrictions.in(t[1], (Object[])v));
else if(t[0].equals("GT"))
dc.add(Restrictions.gt(t[1], v));
else if(t[0].equals("GTE"))
dc.add(Restrictions.ge(t[1],v));
else if(t[0].equals("LT"))
dc.add(Restrictions.lt(t[1],v));
else if(t[0].equals("LTE"))
dc.add(Restrictions.le(t[1],v));
else if(t[0].equals("NOT"))
dc.add(Restrictions.not(Restrictions.like(t[1],v)));
else if(t[0].equals("SORT")){
if(v.toString().equals("1")||v.toString().equalsIgnoreCase("DESC"))
dc.addOrder(Order.desc(t[1]));
else
dc.addOrder(Order.asc(t[1]));
}
}
}
return dc;
}


基本思路是通过对参数的拆分,来区别使用哪种条件限定方法(Like,eq,in,gt,gte,lt,lte等),这里使用了缓存存放实体bean的字段信息。

接着编写测试代码

public class DynamicQueryTest {
private Session session;

@Before
public void init(){
session= HibernateUtil.currentSession();
}

/**
* 如果想从HttpServletRequest中进行绑定,则将params替换成request.getParameterMap();
*/
@Test
public void testQuery(){
//构造查询条件
Map<String,Object> params=new HashMap<>();
params.put("LIKE_name","方%");   //姓方的人
//      params.put("LIKE_address","四川");//家庭地址在四川的人
params.put("IN_address",new String[]{"福建泉州","云南大理"});
params.put("GTE_birth","1996-03-11"); //出生日期大于1996-03-11的人
//      params.put("GT_addDate","2016-01-01");  //录入时间

Result result=query(DynamicQuery.build(IdCard.class, params));

//打印数据
result.getDatas().forEach(d->System.out.println(d));
System.out.println("查询到"+result.getTotal()+"个记录(默认显示前20条记录)");
}

private Result query(DetachedCriteria dc){
Result result=new Result();
Criteria criteria=dc.getExecutableCriteria(session);
result.setDatas(criteria
.setFirstResult(0)
.setMaxResults(20)
.list());

result.setTotal(count(dc.getExecutableCriteria(session)));
return result;
}

private long count(Criteria criteria){
criteria.setProjection(Projections.rowCount());
return ((Number) criteria.uniqueResult()).intValue();
}
}


运行结果



详细的代码可以在这里下载git.oschina.net
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息