在hibernate中查询使用List,Map和类对象定制返回类型

在使用hibernate进行查询时,使用得最多的还是通过构建hql进行查询了。在查询的过程当中,除使用经常的查询对象方法之外,还会遇到查询一个属性,或一组聚集结果的情况。在这种情况下,我们通常就需要对返回的结构进行处理。
    一般情况下,我们通过构建hql,并通过设置query的resultTransformer来定制返回结果的类型,一般设置为map属性,如下所示:
Query query = session.createQuery("hql"); 
query.setResultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP);
来指定查询结果的每一项为一个map。
    不过,随着hibernate的发展,可以在hql中直接使用集合查询语句,如list和map了。以下分别介绍使用List和Map时的查询语句以及查询结果。首先,数据库的数据如下所示:
mysql> select * from p_dictionary;
+-----------------+----+---------+------+--------+--------+
| dictionary_type | id | version | code | forbid | value  |
+-----------------+----+---------+------+--------+--------+
| COUNTY          |  1 |       0 | 001  |        | 四川   |
| COUNTY          |  2 |       0 | 002  |        | 北京   |
| COUNTY          |  3 |       0 | 001  | NULL   | 四川   |
+-----------------+----+---------+------+--------+--------+
3 rows in set (0.00 sec)
以下分别介绍使用list和map的查询语句和查询结果:

使用List

String query = "select new List(p.code, p.value) from Dictionary p";

List list = session.createQuery(query).list();

System.out.println(list);

//结果: [[001, 四川],[002,北京],[001,四川]]

 
使用Map,首先不指定alias,则结果的键就按照查询出来的顺序结果,使用0,1来表示key

String query = "select new Map(p.code, p.value) from Dictionary p";

List list = session.createQuery(query).list();

//结果:[{1=四川, 0=001},{1=北京, 0=002},{1=四川, 0=001}]

 
使用Map,指定alias,则结果中的key则为alias

String query = "select new Map(p.code as code, p.value as value) from Dictionary p";

List list = session.createQuery(query).list();

//结果:[{value=四川, code=001},{value=北京, code=002},{value=四川, code=001}]

 
如果部分使用alias,部分不使用,则使用了alias的将使用alias作为key,没有使用的则仍然使用序号代替,其中序号则为在查询结果的序号

String query = "select new Map(p.code as code, p.value) from Dictionary p";

List list = session.createQuery(query).list();

//结果:[{1=四川, code=001},{1=北京, code=002},{1=四川, code=001}]

--------------------------------------------------------------------------------------------------

select new List(p.name, p.address) from Person as p ;
select将选择出来的属性存入一个List对象中

select new ClassTest(p.name, p.address) from Person as p;
select将选择出来的属性封装成对象,前提是ClassTest支持p.name, p.address的构造函数,

select new Map(p.name as personName) from Person as p ;
select将选中的表达式命名为别名,这种用法与new Map()结合,选择出来的是Map结构,
以personName为key,将实际选择出来的值作为value

--------------------------------------------------------------------------------------

1、集合过滤:

     对于一个已经加载的Customer对象,假设对它的orders集合采用延迟加载机制,那么当调用customer.getOrders().iterator()时,Hibernate就会初始化orders集合,然后到数据库中去加载Customer对象所关联的Order对象,并且填充orders集合,但是很多时候我们其实只是需要关联对象中符合某些条件的一部分对象,而并不需要加载全部关联对象,而对性能带来无谓的开销。这时候我们就可以利用Hibernate的集合过滤功能,来处理关联对象的加载。我们看下面的代码:

List list=session.createFilter(customer.getOrders(),“where this.price>100 order by this.price”).list();

for(int i=0;i<list.size();i++){

 Order order=(Order)list.get(i);

}

在上面代码中通过session.createFilter()方法,创建了一个集合过滤的查询对象,这个方法需要两个参数,第一个参数指定需要进行过滤操作的集合,第二个参数指定过滤集合的条件,方法返回Query对象。这个方法不要求它所要操作的集合对象已经初始化,但是要求包含这个集合对象的实体对象必须处于持久化状态。当执行list()方法时不管持久化对象的集合是否已经初始化,都会到数据库中去检索数据,为了保证在Hibernate缓存中不会出现OID相同的对象,如果集合对象已经初始化,list()方法不会创建新的关联实体对象,而仅仅返回已经存在的关联实体对象。如果集合对象还没有初始化,那么list()方法会创建关联实体对象,但是不会初始化容纳关联实体对象的集合。除了可以向集合对象添加过滤条件进行稽核过滤之外,还可以进行很多其他操作,看下面的代码:

①    、对集合对象进行分页:

List list=session.createFilter(customer.getOders(),”order by this.price asc”)

.setFirstResult(10)

.setMaxResults(50)

.list();

②、检索集合中关联对象的一个属性:

List list=session.createFilter(customer.getOrders(),”select this.ordernumber ”).list();

2、子查询:

  子查询是SQL语句中非常重要的功能特性,它可以在SQL语句中利用另外一条SQL语句的查询结果,在Hibernate中HQL查询同样对子查询功能提供了支持。如下面代码所示:

List list=session.createQuery(“from Customer c where 1>(select count(o) from c.orders o)”).list();

上面的程序查询订单数超过1的所有客户,因此和上面子查询HQL语句对应的SQL语句为:

Select * from Customer c where 1>(select count(o.id) from Order o where c.id=o.customer_ID);

如果子查询返回多条记录,则可以使用下面关键字:

all:表示子查询语句返回的所有记录

any:表示子查询语句返回的任意一条结果

some:与”any”等价

in:与”=any”等价

exists:表示子查询语句至少返回一条记录

例如:查询存在一条订单价格大于100的客户

From Customer c where 100>any(select o.price from c.orders o);

如果在子查询中操作集合,HQL提供了一组操纵集合的函数和属性:

size()函数和size属性:获得集合中元素的数量

minIndex()函数和minIndex属性:对于建立了索引的集合获得最小索引值(关于集合索引参考第一部分映射值类型集合)

minElement()函数和minElement属性:对于包含基本类型的元素集合,获得集合中值最小的元素

maxElement()函数和maxElement属性:对于包含基本类型元素的集合,获得集合中值最大的元素

element()函数:获得集合中所有元素

例如:查询订单数大于0的客户

From Customer c where size(c.orders)>0;或者From Customer c where c.orders.size>0;

以上HQL语句会生成类似如下的SQL语句:

Select * from customer c where 0>(select count(o.id) from order where o. customer_ID =c.id);

注:在HQL中子查询必须出现在where子句中,而且必须用一对圆括号括起来。为什么必须要出现在where字句之后呢?其实我们大家仔细想一下也就知道了,在Hibernate中查询的任何一个实体对象都要有据可循,这个“据”就是Hibernate的主配置文件,也就是说凡是出现在HQL from字句中的实体对象,都必须要在Hibernate主配置文件中有明确的配置。所以在Hibernate中无法支持SQL语句中的那种出现在from字句之后的那种动态视图子查询。


http://blog.youkuaiyun.com/javacoffe/article/details/1733579   (Hibernate 高级查询技巧——集合过滤与子查询)

http://blog.youkuaiyun.com/javacoffe   (Oracle和Hibernate加强学习)

--------------------------------------------------------------------------------------

在hibernate中,用hql语句查询实体类,采用list方法的返回结果为一个List,该List中封装的对象分为以下三种情况:

1.查询全部字段的情况下,如"from 实体类",list中封装的对象为实体类本身,各属性都将得到填充。

2.只查询一个字段,默认情况下,list中封装的是Object对象。

3.查询两个或两个以上的字段,默认情况下,list中封装的是Object[],长度与所查询的字段数一致。

对于后两种情况,用标签遍历时不太方便,因为无法直接转换成实体类的对象。比较简单的解决方法是:

の:在hql中使用select new 包名.类名(属性1,属性2……) from 实体类,同时在实体类中添加带参的构造方法,参数的个数和顺序与(属性1,属性2……) 保持一致,这样我们得到的list中存放的依然是实体类的对象,所查询到的属性得到了填充,使用起来更为方便。

  の:hql查询多表部分字段,select new 包名.表1实体类名(表1.属性1,表2.属性2……) from 表1实体类,表2实体类 where 表1.ID=表2.ID(即相关联的字段),同时在要返回的表1实体类中添加表2的属性和带参的构造方法,参数的个数和顺序与(表1.属性1,表2.属性 2……) 保持一致

例如要查询Problem 中的pid,score,title,totalAccept,totalSubmission,unSee

public class Problem {  

    private int pid;  

    private int score;  

    private int timeLimit;  

    private int memoryLimit;  

    private int totalAccept;  

    private int totalSubmission;  

    private int unSee;  

    private String title;  

    private String description;  

    private String input;  

    private String output;  

      

    public Problem(int pid, int score,String title, int totalAccept, int totalSubmission,  

             int unSee) {  

        super();  

        this.pid = pid;  

        this.score = score;  

        this.totalAccept = totalAccept;  

        this.totalSubmission = totalSubmission;  

        this.unSee = unSee;  

        this.title = title;  

    }  

    //省略getter 和 setter   

}  

查询语句如下

      Query query=session.createQuery("select new Problem(pid,score,title,totalAccept,totalSubmission,unSee) from Problem order by pid");  

        //query.setFirstResult(firstResult); //分页函数   

        //query.setMaxResults(maxResutl);  

        List<Problem> problems=query.list();//返回的还是Problem对象 

关于hibernate的问题: 

我现在有条 

hql="select s.id,s.name,t.id,t.name from User s,Useraddress t where t.id=s.id" 

这条sql里面的User和Useraddress是两个实体类,现在组合查询分别取出来两个实体类里面的两个字段,然后我想再建立一个实体类Result,里面定义这四个结果集里面的字段,能不能执行完这条hql,正好把这个结果集对应到实体类Result里面呢,Result这个实体类,没写映射文件Result.hbm.xml. 

希望能帮下忙 

2种做法 

创建一个class temp 

有属性sid,name,tid,sname,tname 

创建一个构造函数 

public temp(sid,name,tid,sname,tname) 

1.hql中 

List<temp> 

select new temp(s.id,s.name,t.id,t.name) from User s,Useraddress t where t.id=s.id 


2.List 

记录的每一行是object[] 遍历 

object[0] ==s.id 

object[1] ==s.name 

object[2] ==t.id 

object[3] ==t.name 


感谢glamey兄弟的文章,正好解决了当前遇到的问题。原文链接如下:http://glamey.iteye.com/blog/721019

        假设我们现在有一个DTO,其属性包括两张表的属性,我们现在需要将sql语句查询得到的内容转为一个DTO对象,其解决方法如下:  


String sql = "select u.userName as userName ,p.title as title ,p.addTime as addTime from user as u,post as p where u.id=p.userId"  

Query q = factory.getCurrentSession().createSQLQuery(sql).setResultTransformer(Transformers.aliasToBean(PostVO.class));


      上面select中as后面的内容必须和PostVO中属性名一致,这样就可以返回一个针对PostVO的一个集合。 

        其实大家可以看下hibernate这一部分的源码就会发现,主要是使用了AliasToBeanResultTransformer这个类,通过sql的查询,会返回数组,然后hibernate根据数据表的映射,自动帮我们来set对应的字段属性,所以标红的部分务必要跟VO中的属性值一直,要不然会报错的。 

        如果需要的话,大家也可以重写这个类。例如VOResultTransformer。然后在dao中更改成:  


setResultTransformer(new VOResultTransformer(PostVO.class));


  另外,除了以上glamey的方法外,还有一种方法:  

Query q = session.createQuery("select new com.hibernate.MsgInfo(m.id, m.cont, m.topic.title, m.topic.category.name) from Msg m");

List<MsgInfo> list=q.list();

     其中,MsgInfo是DTO。值得注意的是,第二种方法中DTO必须提供带参数的构造方法,并且HQL语句中属性的位置要与构造方法中的位置一一对应。


http://www.blogjava.net/stevenjohn/archive/2012/10/25/390219.html   (这里面讲的非常好)

http://blog.sina.com.cn/s/blog_a2614218010179ym.html   (Hibernate的八大类HQL查询集合)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值