hibernate 查询结果的展现

我们使用hibernate(以下简称h)来管理数据库表的关联关系,基本的原理其实是很简单的,就是将数据库中表之间的关联转移到了实体bean的类之间,配置好了以后h就可以帮我们维持这种关联关系了。这的确带来了很大的方便,我们可以在我们的程序中以hql来面向对象的获取或保存数据了,例如以前我们要查询一个班级里面的学生的信息,自己写sql的话需要关联2张表,而且还要自己手动的将查询到的数据一个一个的取出来,然后封装到我们的bean里面去最后才能字啊jsp中显示出来,这个过程是很繁琐的,有了h,我们就可以不用在sql显式的写这种关联关系了,我们选择将这种关联关系写到h的映射文件中去,这样一来h就帮我们维护这种关系了,我们需要查询班级里面的学生的信息的时候,只要通过hql: from Class  as c  where c.id=:id;就可以得到具体的一个班级的实体对象(假设是c),接着Set<Student> students= c.getStudents();就可以得到该班级里面的所有的学生了。整个过程没有join等任何关联操作,以为这个关联已经由h帮我们维护了,所以我们就可以不管了。


通过上面我们知道,h是通过对象包含对象这样的方式来维护关系的,那么当我们需要查询关联对象的时候,先通过h得到主对象,再调用主对象的get×得到关联对象,就可以获取关联信息了,然后组装数据到jsp上去显示。 我们可以简单的写成:hql=“select new map(c.id as id ,c.name as name,c.students[0].name as  studentname) from Class as  c  where c.id=:id”; 这样就同时完成了数据的查询和组装。将查询到的数据组装到一个map中,as 后面的就是 map的key,map的值就是查询出来的数据了。这种数据组装方式比:

while (it.hasNext()) { 
10 Object[] tuple = (Object[]) it.next(); 
11 Members members = (Members) tuple[ 0 ]; 
12 String className = (String) tuple[ 1 ]; 


要简洁很多。

当然,我们也可以定义自己的实体类来容纳查询出的数据:

selectnew NewMembers(members, classInfo.className) " + 
3 " from Members members, ClassInfo classInfo " + 
4 " where members.level = classInfo.classCode " 



也可以 使用hibernateapi 函数 setResultTransformer 将查询结果存放到我们自定义的bo对象中去:

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));


关于数据组装,有很多方法,不一而论。

我们下面要讨论的是,h在涉及到3张或3张以上的表的复杂的查询的时候,如何使用的问题。


我们知道2张或者一张表的情形使用我们上面介绍的方式就足够了,但是对3张以上的表关联的复杂查询,我们则要比较2中方式的好坏了:


一种方式是仍然将表关系通过配置映射文件交给h来管理,这样一来我们不仅仅要在配置文件里配置多个关系,而且在对应的实体类里面也要加入关联属性,在查询的时候得到主实体对象以后还有多次调用其属性来获取关联表的信息,这样不是不可以,但是是比较繁琐的,稍微不注意就容易出现错误。


如果要查询的表多于5张,最好的建议就是使用native sql来做,也就是通过直接执行sql语句来查询,表间的关联关系直接在sql语句里面写明,不要h来管理,这样一来少了h的配置,二来不需要定义每个表对应的实体类,也算省了很多事情,在使用native sql的时候有一些需要注意的地方:

  Session s = sessionFactory.openSession();
		  
	       
			  String sql="select book.bookname,borr.borrowTime,borr.backTime,pub.pubname,bs.name  bookcasename,book.price from "
+"(select * from tb_borrow where ifback=0) "
+"as borr left join tb_bookinfo book on borr.bookid=book.id join tb_publishing pub "
+"on book.isbn=pub.isbn join tb_bookcase bs "
+" on book.bookcase=bs.id join tb_reader r on borr.readerid=r.id where r.barcode=?";
			  Query query=s.createSQLQuery(sql).addScalar("bookname", Hibernate.STRING) .addScalar("borrowTime", Hibernate.STRING).
					  addScalar("backTime", Hibernate.STRING).addScalar("pubname", Hibernate.STRING).
					  addScalar("bookcasename", Hibernate.STRING).addScalar("price", Hibernate.STRING);   
			  query.setParameter(0, barCode);
			   List list=null;	   
			   try{ 
				   list=query.list();	
			   s.close(); }
			  catch (Exception e)
			  {				  
				  
				  e.printStackTrace();
			  }
		
		return list;


1.  Session session = sessionFactory.openSession();session.createSQLQuery(sql);通过这种方式获得查询对象query。
2.  
  list=query.list();	得到的是一个数组列表(ArrayList),其中列表的每个元素都是object类型的数组,代表查询结果的一条记录,也就是说h会将sql查询出来的其中的每个字段都强制转换成Object类型,然后组成一个数组方到list里面去


3.单纯使用
s.createSQLQuery(sql)往往会报“找不到列”的错误,其实这是h对native sql支持的原因,因为Hibernate是通过使用ResultSetMetadata来判定返回的标量值的实际顺序和类型的,假若某个指定的类型没有被映射,或者不是你所预期的类型那么就会出现上述错误了,所以通过addScalar()明确指出返回什么列以及每个列的类型就可以避免上述错误了

最好你根据实际的类型将得到的object转换成实际的类型,就可以得到这些类型中保存的信息了。


基于SSH的JavaEE开发中采用HQL进行多表查询的几种方法解析


本文所述的多表查询仅在各个表无外键等约束关系下的查询,不涉及join fetch,这里提供以下三种方法进行SSH中的多表查询:

1 采用SQL语句,将结果保存至List中,利用列表下标进行显示

2 采用HQL语句,将查询结果拆分成ORM后的各个对象进行显示

3 采用HQL语句,用HashMap接收查询结果

数据库表结构

在本例中,我们新建两张数据表,其中表的结果如下所示:

–创建学生表

create table stu3401(

         id bigint primary key  identity(1,1),

         name varchar(50) not null,

         password varchar(50) not null

);

 

–创建学生详细信息表

create table stuDetail(

         id int primary key  identity(1,1),

         stuId bigint,

         address varchar(100),

         school varchar(50),

)

 

SQL脚本如下:

–在表stu3401中插入10条数据

insert into stu3401 values(‘a’,3401);

insert into stu3401 values(‘b’,3401);

insert into stu3401 values(‘c’,3401);

insert into stu3401 values(‘d’,3401);

insert into stu3401 values(‘e’,3401);

 

insert into stu3401 values(‘f’,3401);

insert into stu3401 values(‘g’,3401);

insert into stu3401 values(‘h’,3401);

insert into stu3401 values(‘i’,3401);

insert into stu3401 values(‘j’,3401);

 

–在表stuDetail中插入10条数据

insert into stuDetail values(1,’桂林市金鸡路1号’,'桂林电子科技大学a校区’);

insert into stuDetail values(2,’桂林市金鸡路2号’,'桂林电子科技大学b校区’);

insert into stuDetail values(3,’桂林市金鸡路3号’,'桂林电子科技大学c校区’);

insert into stuDetail values(4,’桂林市金鸡路4号’,'桂林电子科技大学d校区’);

insert into stuDetail values(5,’桂林市金鸡路5号’,'桂林电子科技大学e校区’);

 

insert into stuDetail values(6,’桂林市金鸡路6号’,'桂林电子科技大学f校区’);

insert into stuDetail values(7,’桂林市金鸡路7号’,'桂林电子科技大学g校区’);

insert into stuDetail values(8,’桂林市金鸡路8号’,'桂林电子科技大学h校区’);

insert into stuDetail values(9,’桂林市金鸡路9号’,'桂林电子科技大学i校区’);

insert into stuDetail values(10,’桂林市金鸡路10号’,'桂林电子科技大学j校区’);

1 采用SQL语句,将结果保存至List中,利用列表下标进行显示

1.1 概况

这种方法采用SQL语句,未将数据表的关系(R)进行对象(O)映射(M),因此,我们在此将查询得到的数据用ArrayList进行接收,并在前台用列表的下标进行显示,具体操作如下:

1.2 DAO层

首先我们采用SQL语句进行查询,其中DAO中代码如下:

         /*

          * 使用SQL语言对数据库进行查询,将结果返回至一个列表中

          * */

         public List queryBySQL(String queryString)

         {

                   log.debug(“query data using function createSQLQuery and return a list”);

                   try {

                            return this.getSession().createSQLQuery(queryString).list();

                   } catch (RuntimeException re) {

                            // TODO: handle exception

                            log.error(“query error”,re);

                            throw re;

                   }

         }

1.3 业务层

Action中的代码如下:

    public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response) {

       String queryString=”select * from stu3401 s,stuDetail t where s.id=t.stuId”;

       List stuList = stu3401Service.queryBySQL(queryString);

       request.setAttribute(“result”, stuList);

       return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[[1, a, 3401, 1, 1, 桂林市金鸡路1号, 桂林电子科技大学a校区],

[2, b, 3401, 2, 2, 桂林市金鸡路2号, 桂林电子科技大学b校区],

[3, c, 3401, 3, 3, 桂林市金鸡路3号, 桂林电子科技大学c校区]

[4, d, 3401, 4, 4, 桂林市金鸡路4号, 桂林电子科技大学d校区],

[5, e, 3401, 5, 5, 桂林市金鸡路5号, 桂林电子科技大学e校区],

[6, f, 3401, 6, 6, 桂林市金鸡路6号, 桂林电子科技大学f校区],

[7, g, 3401, 7, 7, 桂林市金鸡路7号, 桂林电子科技大学g校区],

[8, h, 3401, 8, 8, 桂林市金鸡路8号, 桂林电子科技大学h校区],

[9, i, 3401, 9, 9, 桂林市金鸡路9号, 桂林电子科技大学i校区],

[10, j, 3401, 10, 10, 桂林市金鸡路10号, 桂林电子科技大学j校区],null]

它是一个长度为11的数组列表obj1[11](ArrayList,使用数组实现List数据结构,实质上就是一个长度可变的数组):该列表可描述为Object[11] obj1 = {obj10[7],obj11[7],…obj19[7],null}(注意最后还有一个null,但是其size为10,modCount也为10),其中的每一个元素是一个长度为7的Object类型的对象列表(数组),这里表示为obj1j[7],(j=0,1,…9)。我们以j = 0为例,对于对象列表obj10[7],它包含7个属性,分别对应两张数据表中的7个字段,其中的每个字段都被强制类型转换成Object类型(因为Object类是所有类的父类,)。因此,stuList就可理解为一个对象列表(数组)的列表(数组)。

1.4 表示层

前台JSP页面代码如下:

<table width=”600px” align=”center”>

    <thead>

        <tr>

           <td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

        </tr>

    </thead>

    <tbody>

        <c:if test=”${!empty result}”>

           <c:forEach items=”${result}” var=”Item”>

               <tr>

                  <td>${Item[1]}</td>

                  <td>${Item[5]}</td>

                  <td>${Item[6]}</td>

               </tr>

           </c:forEach>

        </c:if>

       

        <c:if test=”${empty result}”>

           <tr>

               <td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

                  οnmοuseοver=”this.bgColor = ‘#DEE7FF’;”

                  οnmοuseοut=”this.bgColor=’#EFF3F7′;”>

                  没有找到相应的记录

              </td>

           </tr>

        </c:if>

    </tbody>

  </table>

1.5 小结

这种方法的弊端在于当我们对数据库进行维护时,若需要更改(如添加或删除)某些字段,则在前台JSP页面中,我们还需要对其下标进行修改,一方面给开发维护带来很大不便,另一方面也容易出错。

2采用HQL语句,将查询结果拆分成ORM后的各个对象进行显示

2.1 概况

与方法一不同,这种方法对数据表的关系进行了ORM映射,也就是我们可以对查询的结果进行对象的操作。在本例中,因为涉及到两张表的查询,因此我们需要对查询结果进行分拆后再强制类型转换,具体实现如下:

2.2 DAO层

以下是DAO层的代码:

          /*

          * 使用SQL语言对数据库进行查询,将结果返回至一个列表中

          * */

    public List queryByHql(String queryString)

    {

       log.debug(“query data from two tables and show data using hql object”);

       try {

           return getHibernateTemplate().find(queryString);

       } catch (RuntimeException re) {

           // TODO: handle exception

           log.error(“query error”,re);

           throw re;

       }

    }

2.3 业务逻辑层

Action中的代码如下:

    public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response) {

 

       String queryString=”from Stu3401 s,StuDetail t where s.id=t.stuId”;

       List stuList = stu3401Service.queryByHql(queryString);

       List<Stu3401> stuList1=new ArrayList<Stu3401>();

       List<StuDetail> stuList2=new ArrayList<StuDetail>();

       Object[] obj = null;

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

       {

           obj = (Object[])stuList.get(i);

           stuList1.add((Stu3401)obj[0]);

           stuList2.add((StuDetail)obj[1]);

       }

       request.setAttribute(“result1″, stuList1);//保存表1数据

       request.setAttribute(“result2″, stuList2);//保存表2数据

                   return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[[com.lyw.loginCoridc.model.domain.Stu3401@130c35c, com.lyw.loginCoridc.model.domain.StuDetail@db8522], [com.lyw.loginCoridc.model.domain.Stu3401@19a64, com.lyw.loginCoridc.model.domain.StuDetail@13f54ae],

……

……

[com.lyw.loginCoridc.model.domain.Stu3401@5b77c, com.lyw.loginCoridc.model.domain.StuDetail@151685f], null]

它也是一个长度为11的数组列表,假设定义为obj1[11] = {obj10[2],obj11[2],…,obj19[2],null},其中的每一个元素是一个长度为2的Ojbect类型的对象列表(数组),这里表示为obj1j[2],(j=0,1,…9)。我们以j = 0为例,对于对象列表obj10[2],其第一个元素是第一张数据表所映射的Stu3401类型的对象,包括id,name和password三个属性;第二个元素是第二张数据表所映射的StuDetail类型的对象,包括id,address,school和stuId四个属性。因此我们可以通过对象对查询进过进行保存,代码如上。

2.4 表示层

前台JSP页面代码如下:

  <table width=”600px” align=”center”>

    <thead>

        <tr>

           <td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

        </tr>

    </thead>

    <tbody>

        <c:if test=”${!(empty result1 || empty result2)}”>

           <c:forEach items=”${result1}” var=”Item1″ varStatus=”s”>

               <c:forEach items=”${result2}” var=”Item2″ begin=”${s.index}” step=”${fn:length(result1)-s.index}”>

                   <tr>

                      <td>${Item1.name}</td>

                      <td>${Item2.address}</td>

                      <td>${Item2.school}</td>

                   </tr>

               </c:forEach>

           </c:forEach>

        </c:if>

       

        <c:if test=”${empty result1 || empty result2}”>

           <tr>

               <td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

                  οnmοuseοver=”this.bgColor = ‘#DEE7FF’;”

                  οnmοuseοut=”this.bgColor=’#EFF3F7′;”>

                  没有找到相应的记录

              </td>

           </tr>

        </c:if>

    </tbody>

  </table>

在上面代码中,为了求得列表的长度,我们引入了标签fn,因此还需在页面上导入JSTL标签库:

<%@ taglib prefix=”fn” uri=”http://java.sun.com/jsp/jstl/functions” %>

关于fn标签函数的函数说明可参见:http://www.coridc.com/archives/2349.html

2.5 小结

         这种方法相对第一种方法来讲,最大的好处就是能够通过对象的属性进行显示,而不再担心下标的问题。但该方法也存在一个问题,当查询所涉及到N张表时,我们就需要向前台传入N个参数,而且在前台的Foreach循环控制上,会显得很麻烦。

3 采用HQL语句,用HashMap接收查询结果

3.1 概况

在方法二中,我们从后台传递N(N表示数据查询所涉及到的表的数量)个列表至前台,由此带来的不便在2.5节中已略有阐述。在方法三中,我们将采用HashMap来接收查询结果并传递到前台,详细操作如下:

3.2 DAO层

因为方法三与方法二都采用HQL语句查询,因此方法三的DAO层代码与方法二相同。

3.3 业务逻辑层

Action中的代码如下:

    public ActionForward showByListAndHqlOjbject(ActionMapping mapping, ActionForm form,

           HttpServletRequest request, HttpServletResponse response) {

 

       String queryString1=”select new map(s.name as name,t.address as address,t.school as school) from Stu3401 s,StuDetail t where s.id=t.stuId”;

       List stuList = stu3401Service.queryByHql(queryString1);

       request.setAttribute(“result”, stuList);

                   return mapping.findForward(“success”);

}

通过Debug我们可以发现,采用这种方法我们得到的stuList是一个ArrayList,其值如下所示:

[{address=桂林市金鸡路1号, school=桂林电子科技大学a校区, name=a},

{address=桂林市金鸡路2号, school=桂林电子科技大学b校区, name=b},

{address=桂林市金鸡路3号, school=桂林电子科技大学c校区, name=c},

{address=桂林市金鸡路4号, school=桂林电子科技大学d校区, name=d},

{address=桂林市金鸡路5号, school=桂林电子科技大学e校区, name=e},

{address=桂林市金鸡路6号, school=桂林电子科技大学f校区, name=f},

{address=桂林市金鸡路7号, school=桂林电子科技大学g校区, name=g},

{address=桂林市金鸡路8号, school=桂林电子科技大学h校区, name=h},

{address=桂林市金鸡路9号, school=桂林电子科技大学i校区, name=i},

{address=桂林市金鸡路10号, school=桂林电子科技大学j校区, name=j}]

它是一个长度为10的数组列表,列表的每一个元素都是一个HashMap<K,V>,如stuList[0] = {address=桂林市金鸡路1号, school=桂林电子科技大学a校区, name=a},那么我们可以在JSP页面直接通过HashMap的Key来取得相对应的Value,前台代码见3.4节。

3.4 表示层

前台JSP页面代码如下:

  <table width=”600px” align=”center”>

    <thead>

        <tr>

           <td width=”100px”>账号</td><td width=”300px”>家庭住址</td><td width=”300px”>学校</td>

        </tr>

    </thead>

    <tbody>

        <c:if test=”${!empty result}”>

           <c:forEach items=”${result}” var=”Item”>

               <tr>

                  <td>${Item.name}</td>

                  <td>${Item.address}</td>

                  <td>${Item.school}</td>

               </tr>

           </c:forEach>

        </c:if>

       

        <c:if test=”${empty result}”>

           <tr>

               <td colspan=”20″ align=”center” bgcolor=”#EFF3F7″

                  οnmοuseοver=”this.bgColor = ‘#DEE7FF’;”

                  οnmοuseοut=”this.bgColor=’#EFF3F7′;”>

                  没有找到相应的记录

              </td>

           </tr>

        </c:if>

    </tbody>

  </table>

3.5 小结

很明显,这种方法比第一种和第二种方法要简便的多,而且易于维护,代码量小,剩下的,你们懂的。













评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

walkingmanc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值