`

使用HIBERNATE的DetachedCriteria无限级联取部份字段的查询结果集转换

阅读更多
--后记,本文所讲的实现在我的另一篇博客中提供了完整的源代码与编译好的JAR包,可供下载使用。http://lgdlgd.iteye.com/admin/blogs/619370

有经验的朋友都知道,列表查询时,一般不会查这个实体的全部字段,取部份字段的DetachedCriteria查询,常常 会用到AliasToBeanResultTransformer类把结果转换成POJO:
criteria.setResultTransformer(Transformers.aliasToBean(pojoClass));

但很显然,AliasToBeanResultTransformer类对结果集的封装是很简陋的,只能对本POJO的属性进行封装。
比如USER表有id,name,email,organization(组织,另一个实体),如果查询USER时要包含organization实体的name属性,但不要整个oganization,AliasToBeanResultTransformer就无能为力了,我写了另一个结果转换器来完成这个功能,其中用到OGNL工具包,Struts2和WEBWORK就是使用它把前台页面传回的参数填充ACTION里的属性对象的,我的灵感也是来源于此。

查询方法代码:


////////SERVICE中查询的方法
public List<User> findUsers(){
//要查的部份字段,ID,用户名和所在组织的名称
String[] columns = {"id","name","organization.name"};
//构造查询器
DetachedCriteria criteria = DetachedCriteria.forClass(User.class,"_user");
//筛选字段
DetachedCriteriaUntils.selectColumn(criteria,columns,Class pojoClass, String rootAlias,boolean forJoinTable);
//查询数据库
return userDAO.findByCriteria(criteria)
}


查询方法结束,下面这个方法就是如何筛选字段,不过只是部份代码,还有几个方法没有全列出,重点看最后几行

/**
	 * 该方法提供DetachedCriteria对查询字段的封装,
	 * 可支持无限级联取部分字段  ser.organization.parentOrganization.parentOrganization.orgName
	 * 但请注意1点 ,连接采用内联,级联越多,结果集可能就越少;
	 * @param columnNames
	 *            字符串数组,以数据的形式接收要查询的字段属性,如String[] column={"属性1","属性2","属性3"};
	 * @param pojoClass
	 *            实体类的Class,如Mobile.class;
	 * @param rootAials
	 *            为要查询的POJO对象指定一个别名
	 * @return DetachedCriteria 的一个对象,如果需要查询条件,在些对象后追加查询条件。
	 * 
	 * @param forJoinTable 是否多表连接查询
	 */
	public static void selectColumn(DetachedCriteria criteria, String[] columnNames,
			Class<? extends BaseModel> pojoClass, String rootAlias,boolean forJoinTable) {
		if (null == columnNames) {
			return;
		}
	
		//使用这个临时变量集合,是因为dinstinct关键字要放在最前面,而distinct关键字要在下面才决定放不放,
		List<Projection> tempProjectionList = new ArrayList<Projection>();;
		
		Set<String> aliases = getAliasFromRequest();
		boolean hasJoniTable = false;
		for (String property : columnNames) {
			if(property.contains(POINT)){
				String[] propertyChain = property.split("\\.");
				if(aliases==null){aliases=new HashSet<String>(3);}
				createAlias(criteria,rootAlias,aliases,propertyChain,0);
				tempProjectionList.add(Projections.property(getAliasFromPropertyChainString(property)).as(property));
				hasJoniTable = true;
			}else{
				tempProjectionList.add(Projections.property(rootAlias + POINT + property).as(property));
			}
		}
		
		ProjectionList projectionList = Projections.projectionList();
		if(hasJoniTable || forJoinTable ||  getHasJoinTatleFromRequest()){//这个一定要放在tempProjectionList的前面,因为distinct要在最前面
			projectionList.add(Projections.distinct(Projections.id()));
		}
		
		for (Projection proj : tempProjectionList) {
			projectionList.add(proj);
		}
		
		criteria.setProjection(projectionList);
		
		if(!hasJoniTable){
			criteria.setResultTransformer(Transformers.aliasToBean(pojoClass));
		}else{//注意,重点就在这里,这里检测到如果有类类似于user.organization.name这种字段,就表示是级联其它表的部份字段,那么要使用下面的这个EscAliasToBean来转换结果集,而不能使用上面那个HIBERNATE提供的类
			criteria.setResultTransformer(new EscAliasToBean(pojoClass));
		}
	}



      本文主要不是讨论如何筛选字段,所以上面有部份方法没有再贴出来。下面是EscAliasToBean类的完整代码


package com.lgdlgd.hibernate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ognl.Ognl;

import org.hibernate.HibernateException;
import org.hibernate.transform.ResultTransformer;

import com.opensymphony.xwork2.util.InstantiatingNullHandler;
import com.opensymphony.xwork2.util.OgnlUtil;

/**
 * 支持属性为自定义对象的结果集转换的部份属性查询
 */
@SuppressWarnings({"serial","unchecked"})
public class EscAliasToBean implements ResultTransformer {

	private static final Map<String,Boolean> context = new HashMap<String,Boolean>(1);
	static{
		context.put(InstantiatingNullHandler.CREATE_NULL_OBJECTS, true);
	}
	
	/** POJO的class */
	private final Class resultClass;

	
	public EscAliasToBean(Class pojoClass) {
		if(pojoClass==null) throw new IllegalArgumentException("resultClass cannot be null");
		this.resultClass = pojoClass;		
	}

	@Override
	public List transformList(List collection) {
		return collection;
	}

	/**
	 * 结果集转换
	 * @param tuple 属性值集合
	 * @param aliases 属性名集合,就是上面的{id,name,organization.name};
	 * @return 单个POJO实例--查询结果
	 */
	@Override
	public Object transformTuple(Object[] tuple, String[] aliases) {
		try {
			Object root = resultClass.newInstance();
			for (int i = 0; i < aliases.length; i++) {
				Ognl.setValue(OgnlUtil.compile(aliases[i]), context, root, tuple[i]);
			}
			return root;
		} catch (Exception e) {
			throw new HibernateException(e.getMessage(),e);
		}
	}

}




到此完成,结果的转换比HIBERNATE的那个原生转换器还要简洁,本来这个类完全可以代替它的,只不过这个用到的其它的框架,牵连太多,功能虽强大,但恐在简单环境里速度不如原来的好。如果有朋友想要探讨如何筛选字段的部份,也可以提出来。


5
0
分享到:
评论
10 楼 ming_fanglin 2010-04-22  
博主,我有hibernate方面的问题,能加下我的qq么  174725498
9 楼 xiaoyuqi00 2009-12-12  
首先谢谢您的解答。

第一次用ssh大型的项目,遇到的问题很多,

一:
1、先save(),此时没有进行数据的插入,
2、再调用list(),此时当插入的那条数据就无法查询出,该怎么解决?

二:
1、我们用的opensessioninview,事务交给spring处理,问题都出现了。当你调用fluse的时候数据已经进数据库,没办法在控制了,但有些数据用必须立即进数据库然后查出。

请加我QQ:290851952。本人真心求教。

8 楼 lgdlgd 2009-12-11  
1、如果你使用HIBERNATE进行插入,那么插入完了不需要查,原来的对象马上就可以用。
2、如果你通过查询的方法获得原来的对象,如下
Java代码
userDao.save(user);  
userDao.find("from User u where u.name='xiaoyuqi00'"); 

userDao.save(user);
userDao.find("from User u where u.name='xiaoyuqi00'");

这时在find执行前HIBERNATE会先执行插入,不需要你担心flush的问题,另外,如果在此事务未结束前,发生可回滚的异常,这个条数据依然会被回滚,不需要担心数据问题。

当然,这些都有个前提,我的项目是由SPRING来控制事务的,上术情况的事务也要交由外层来控制。
7 楼 xiaoyuqi00 2009-12-11  
关于hibernate和事务的问题。


、需要立即插入数据时,需要调用fluse方法,但是调用后,事务又无法控制?

、如果需要刚刚插入的数据怎么获得(没有调用fluse,数据库目前还没有数据)?


请指点下
6 楼 xiaoyuqi00 2009-12-07  
lgdlgd 写道
xiaoyuqi00 写道
博主,用的DetachedCriteria的createAlias()去关联查询

查询的是关联表的所有字段,我看了你的方法,有点麻烦,

我们也没用struts2,请问DetachedCriteria有没有像HQL那样,

直接设置你要查询哪些字段,他就帮你查询你要查询的。

我想他应该有吧,要不每次都要全查,不是很浪费效率

请问博主知道么?

我想知道,

关注下

DetachedCriteria取部份字段的方式就是下面这样的,据我所知,只有这一种
ProjectionList projectionList = Projections.projectionList();  
...  
criteria.setProjection(projectionList); 

关于你说的麻烦,我也同意,但是你要把这些麻烦的东西像我一样封装起来,别人使用的时候你下面这样
String[] columns = new String[]{property1,property2,property3.property4};
DetachedCriteria criteria = getDetachedCriteria(POJO.class,columns,alias);
DAO.findByCriteria(criteria);

那么用起来就不麻烦了,你觉得呢?而且你把这封装起来作为基础框架,以后如果你发现有更好的方法的时候,把框架改一改,然后你的业务逻辑也不需要改,这不挺好吗?



博主,我有些hibernate的问题,希望和您请教下,麻烦加我QQ:290851952 谢
5 楼 lgdlgd 2009-09-26  
xiaoyuqi00 写道
博主,用的DetachedCriteria的createAlias()去关联查询

查询的是关联表的所有字段,我看了你的方法,有点麻烦,

我们也没用struts2,请问DetachedCriteria有没有像HQL那样,

直接设置你要查询哪些字段,他就帮你查询你要查询的。

我想他应该有吧,要不每次都要全查,不是很浪费效率

请问博主知道么?

我想知道,

关注下

DetachedCriteria取部份字段的方式就是下面这样的,据我所知,只有这一种
ProjectionList projectionList = Projections.projectionList();  
...  
criteria.setProjection(projectionList); 

关于你说的麻烦,我也同意,但是你要把这些麻烦的东西像我一样封装起来,别人使用的时候你下面这样
String[] columns = new String[]{property1,property2,property3.property4};
DetachedCriteria criteria = getDetachedCriteria(POJO.class,columns,alias);
DAO.findByCriteria(criteria);

那么用起来就不麻烦了,你觉得呢?而且你把这封装起来作为基础框架,以后如果你发现有更好的方法的时候,把框架改一改,然后你的业务逻辑也不需要改,这不挺好吗?
4 楼 xiarilian12 2009-09-26  
xiaoyuqi00 写道
博主,用的DetachedCriteria的createAlias()去关联查询

查询的是关联表的所有字段,我看了你的方法,有点麻烦,

我们也没用struts2,请问DetachedCriteria有没有像HQL那样,

直接设置你要查询哪些字段,他就帮你查询你要查询的。

我想他应该有吧,要不每次都要全查,不是很浪费效率

请问博主知道么?

我想知道,

关注下

同问。。。
3 楼 xiaoyuqi00 2009-09-26  
博主,用的DetachedCriteria的createAlias()去关联查询

查询的是关联表的所有字段,我看了你的方法,有点麻烦,

我们也没用struts2,请问DetachedCriteria有没有像HQL那样,

直接设置你要查询哪些字段,他就帮你查询你要查询的。

我想他应该有吧,要不每次都要全查,不是很浪费效率

请问博主知道么?

我想知道,

关注下
2 楼 lgdlgd 2009-09-22  
部份字段查询时,你要用到以下代码

ProjectionList projectionList = Projections.projectionList(); 
....
取部份字段,并创建级联关系
....
criteria.setProjection(projectionList); 

用了这个代码,你必须使用下面的代码来将结果集转换成POJO的集合,否则返回的就是对象数组,当然如果你不在乎,愿意自已封装的话,你可以不要下面的代码,也就可以不需要用OGNL组件。
criteria.setResultTransformer(...));   

1 楼 黑猪王子 2009-09-22  
突然想到一个疑问了  为什么要重新组装结果Bean呢?   如果可以关联起来的Bean直接都是有getter的,返回回来的Bean里直接getter就可以了,不需要在ognl组装一个了吧?

我直接用for循环加别名实现的无限级关联

相关推荐

    SSH+级联菜单应用案例

    - 数据库查询效率:为了提高性能,可以使用预编译的SQL语句(Hibernate的Criteria API或HQL的DetachedCriteria)。 - 视图的懒加载:避免一次性加载所有菜单,而是根据用户的交互动态加载需要的子菜单。 - 安全性...

    Hibernate-基础联表模板

    综上所述,"Hibernate-基础联表模板"涵盖了Hibernate中关于联表查询的基础知识,包括各种查询方式、关联关系的定义、Fetch策略以及查询结果的处理等,是开发者进行数据库操作的有力助手。通过这个模板,开发者可以...

    《精通Hibernate》电子版(孙卫琴)

    书中讲解了HQL的基本语法,包括选择、投影、连接、分组、排序等操作,以及查询结果的处理。此外,还介绍了Criteria API,一种更加面向对象的查询方式。 五、 Criteria与DetachedCriteria Criteria API提供了动态...

    孙卫琴精通hibernate part2

    《孙卫琴精通Hibernate Part2》是一份深入学习Hibernate框架的教程,主要涵盖了该框架的高级特性和实战应用。在本教程的第二部分,我们将会更深入地探讨Hibernate的各个重要方面,帮助开发者提升数据库操作的效率和...

    《深入浅出Hibernate》.pdf

    《深入浅出Hibernate》这本书是针对初学者设计的,旨在帮助读者快速掌握Hibernate这一流行的Java对象关系映射(ORM)框架。Hibernate是一个强大的工具,它简化了Java应用程序与数据库之间的交互,通过提供一种抽象...

    hibernate v3.04中文参考手册

    - 查询缓存:缓存查询结果,提高效率。 9. **实体状态与生命周期** - 新建(Transient)、持久化(Persistent)、游离(Detached)、删除(Removed)四种状态。 - 生命周期转换:对象的保存、加载、更新和删除...

    hibernate 3.2.2

    2. 移动对象:`DetachedCriteria`允许在不打开Session的情况下构建查询,然后在需要时再进行执行。 总之,Hibernate 3.2.2作为一款成熟且稳定的ORM框架,其丰富的功能和良好的社区支持使得它在众多项目中依然保持...

    hibernate3.2-中文帮助文档

    这份文档全面介绍了Hibernate框架,一个广泛使用的Java对象关系映射(ORM)工具,它允许开发者在Java应用中使用SQL数据库而无需直接编写SQL语句。下面我们将深入探讨该文档涵盖的主要知识点。 1. **Hibernate 概述*...

    Hibernate3.3 API中文版

    此外,`Criteria` API提供了一种类型安全的方式来构建动态查询,而`DetachedCriteria`则允许我们在不使用Session的情况下构建查询条件。 关联映射是Hibernate的另一个重要特性。`@OneToOne`、`@OneToMany`、`@...

    Hibernate全部笔记

    3. **查询缓存**:存储查询结果,提高性能。 **八、高级特性** 1. **延迟加载(Lazy Loading)**:按需加载关联对象,避免加载大量无用数据。 2. **级联操作**:在操作主对象时,可以自动处理关联对象的增删改查。 ...

    hibernate 3.5.5 常用jar包

    11. **Criteria API中的Projections**:用于定义查询结果的返回类型,如sum、avg、count等。 12. **SessionFactory**:是线程安全的,负责创建Session实例,一般在应用启动时初始化一次。 13. **第二级缓存**:...

    Hibernate框架知识点的练习代码

    通过Criteria、DetachedCriteria和Expression,我们可以构建复杂的查询条件。 6. **缓存机制**:Hibernate支持一级缓存(Session级别的)和二级缓存(SessionFactory级别的)。缓存可以提高性能,减少对数据库的...

    Hibernate In Action中文版电子书

    14. **性能优化**:包括合理使用批处理、延迟加载、缓存、优化查询以及避免N+1查询问题等,都是提升Hibernate应用性能的关键。 15. **事务隔离级别**:理解数据库的四种事务隔离级别(读未提交、读已提交、可重复读...

    Hibernate_3.2.0_Reference_zh_CN.rar hibernate中文api

    10. **Criteria API与DetachedCriteria**:Criteria API用于在Session中执行查询,而DetachedCriteria则允许在Session之外构建查询条件,再在Session中执行。 11. **Criteria与HQL的比较**:两者都是ORM查询方式,...

    Hibernate备课笔记.pdf

    Hibernate是一款开源的对象关系映射(ORM)框架,它允许开发者使用面向对象的编程方式来操作数据库,极大地简化了Java应用程序对数据库的操作。本备课笔记将深入探讨Hibernate的核心概念、配置、实体映射、查询语言...

    深入浅出Hibernate

    8. ** Criteria API的DetachedCriteria**:DetachedCriteria允许预编译查询条件,适用于分页查询或延迟加载。 9. **懒加载与立即加载**:Hibernate支持懒加载(Lazy Loading),即关联对象只有在真正需要时才会被...

    ( [尚硅谷]_佟刚_Hibernate面试题分析.zip

    1. **Hibernate概述**:Hibernate是一个开放源代码的对象关系映射(ORM)框架,它自动管理Java应用程序与数据库之间的交互,将对象模型转换为关系数据库模型,简化了数据访问。 2. **配置文件**:Hibernate的工作...

    hibernate中文文档

    《Hibernate中文文档》是针对Java开发人员的一份重要参考资料,它详细阐述了Hibernate框架的使用方法、API详解以及最佳实践。Hibernate是一个强大的对象关系映射(ORM)框架,它简化了Java应用程序对数据库的访问,...

    hibernate开发指南

    《Hibernate开发指南》是一本专为Java开发者设计的详尽指南,旨在帮助他们掌握和熟练使用Hibernate这一强大的对象关系映射(ORM)框架。Hibernate是一个开源的Java库,它简化了数据库应用程序的开发,通过将Java类与...

    Hibernate开发所需的jar包

    - 查询缓存:对查询结果进行缓存,减少对数据库的访问。 7. 数据库连接池: - Hibernate可与多种数据库连接池集成,如C3P0、DBCP、HikariCP等,以提高数据库连接的复用性和系统性能。 8. 异常处理: - ...

Global site tag (gtag.js) - Google Analytics