- 浏览: 18449 次
- 性别:
- 来自: 成都
hql多表查询
这是工作中遇到的一个小问题,有关于用户、部门、角色的条件查询,业务需求是一个多条件用户搜索,用户对象包含一个所属部门对象和角色集合,用户填写的条件有名称、登录名....(省略)、所属部门、拥有角色,也就是在后面两个条件的过滤上卡住。
参看在网上找到的这篇内容,问题顺利解决,至于hibernate的性能问题,暂未考虑。
HQL的多表查询
对象之间总是有各种各样的关系,关联关系是类之间最常见的关系。多表查询是HQL中的强大功能之一,包括内连接、左连接和右连接等。多表查询的设置及运行都比较麻烦,在运行本节中的示例时,务必保证每一步都没有错误。
表之间的关联关系
在数据库joblog中用到了3个表:student(学生表)、course(课程表)和sc(选课表)。这些表的详细信息见6.1.1节“示例中用到的默认数据库表和数据”。在现实模型中,一个学生可以选择多门课程,一个课程可以被多个学生选择,student和course是多对多的关联关系。为了便于演示HQL的多表查询,本节中假设student和course之间是单向关联关系。
在多对多的关联关系中,一般来说有个中间表,这个表描述了多对多关系,这就是选课表sc,sc每一行数据代表一个学生的选课和成绩。
各个表的主键、外键设置如下。
student表的主键是id字段。
course表的主键是id字段。
sc表的主键是id字段。
sc表中的Sno字段是student表id字段的外键。
sc表中的Cno字段是course表id字段的外键。
图6-8是3个表之间关系的直观表示。
图6-8 3个表之间的关系
在MySQL Query Browser中设置好上述关系。如果此处设置不正确,可能会影响多表连接查询。其中sc表的建表信息如下(其中包含了外键关系)。
CREATE TABLE 'joblog'. 'sc' (
'id' int(10) unsigned NOT NULL auto_increment COMMENT 'id',
'Sno' int(10) unsigned NOT NULL default '0' COMMENT '学号',
'Cno' int(10) unsigned NOT NULL default '0' COMMENT '课程号',
'Grade' int(10) unsigned default NULL COMMENT '成绩',
PRIMARY KEY ('id'),
KEY 'FK_sc_1' ('Sno'),
KEY 'FK_sc_2' ('Cno'),
CONSTRAINT 'FK_sc_1' FOREIGN KEY ('Sno') REFERENCES 'student' ('id'), /* 外键信息 */
CONSTRAINT 'FK_sc_2' FOREIGN KEY ('Cno') REFERENCES 'course' ('id') /* 外键信息 */
) ENGINE=InnoDB DEFAULT CHARSET=gb2312;
表中的数据
这一节中用到了3个表的数据,student表和course表的数据如6.1节中图6-2和6-4所示,但是sc表的内容变为图6-9所示的数据,其中Sno和Cno存储的分别是student表和course表中对应的主键值。
图6-9 本节中所用的表sc中的内容
修改持久化类
Student对象和Course对象之间是多对多的关系。此处使用的是单向关联,仅仅建立从Student到Course的单向关联。如图6-10所示,仅有Student到Course的单向关联。
图6-10 Student到Course类的单向关联
为了建立Student到Course的单向关联关系,在Student.java中新加一个属性course。course属性是Set型的,可以在这个属性中加入多个Course对象,建立起关联关系。下面是加入course属性后的源代码,粗体部分为加入的代码。
package hibernate.ch06;
import java.util.HashSet;
import java.util.Set;
public class Student implements java.io.Serializable {
private Integer id; //ID
private Integer sno; //学号
private String sname; //姓名
private String ssex; //性别
private String sdept; //系部
private Integer sage; //年龄
private String saddress; //住址
private Set course=new HashSet(); //所选课程
public Student() {
}
//此处省略其他的构造方法
//此处省略getter/setter访问器
//course属性的get访问器
public Set getCourse() {
return course;
}
//course属性的set访问器
public void setCourse(Set course) {
this.course = course;
}
}
持久化类Course.java和SC.java无需修改。
在映射文件中加入关联信息
在Student.hbm.xml映射配置文件中,加入Student到Course的映射信息。关于如何映射关联关系,将在第8章讲解,读者可暂时按照下面的设置,具体含义等阅读完第八章便可理解。具体代码如下。
<set name="course" table="sc" lazy="false" cascade="save-update">
<key column="sno" />
<many-to-many class="hibernate.ch06.Course" column="cno" />
</set>
说明如下。
<set>元素是和<class>元素平行的元素。<set>元素表明将要映射的字段对应着一个集合。<set>元素包含多个属性,其中:name属性用于设置映射的持久化类的属性名称,在本例中为Student表的course属性;table属性表示多对多关联关系的中间表名称,此处为sc表;cascade表示当保存或者更新Student实例时,是否保存或更新Course 对象。
<set>元素的子元素<key column="sno" />设定与student表关联的中间表sc的外键sno。
<set>元素的子元素<many-to-many>用于设定多对多关系。在该元素中,class属性用于设定多对多关系中,与Student类关联的类Course类;column属性设定中间表与course表连接的外键cno。
完整的配置文件Student.hbm.xml如下所示。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.ch06.Student" table="student" catalog="joblog">
<id name="id" type="integer">
<column name="id" />
<generator class="identity"></generator>
</id>
<!--映射学号-->
<property name="sno" type="integer">
<column name="Sno" not-null="true" />
</property>
<!--映射姓名-->
<property name="sname" type="string">
<column name="Sname" length="45" />
</property>
<!--映射系部-->
<property name="sdept" type="string">
<column name="Sdept" length="10" />
</property>
<!--映射年龄-->
<property name="sage" type="integer">
<column name="Sage" />
</property>
<!--映射性别-->
<property name="ssex" type="string">
<column name="Ssex" length="2" />
</property>
<!--映射住址-->
<property name="saddress" type="string">
<column name="Saddress" length="45" />
</property>
<!--联接-->
<set name="course" table="sc" lazy="false" cascade="save-update">
<key column="sno" />
<many-to-many class="hibernate.ch06.Course" column="cno" /> <!--多对多-->
</set>
</class>
</hibernate-mapping>
左外连接
左外连接(Left Outer Join)查询出左表对应的复合条件的所有记录,如查询李晓梅同学的选课信息。下面是类HQLLeftOuterJoinQuery的源代码。
package hibernate.ch06;
import hibernate.HibernateSessionFactory;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
public class HQLLeftOuterJoinQuery {
public static void main(String[] args) {
Session session=HibernateSessionFactory.currentSession();
//HQL查询语句
String hql="from Student s left join s.course c where s.sname='李晓梅'";
Query query=session.createQuery(hql); //创建查询
List list=query.list(); //执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Object[] obj=(Object[])it.next();
Student stu=(Student)obj[0];
Course course=(Course)obj[1];
System.out.println("*********学生信息及其选课信息******************");
if(course!=null){
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t"+
"课程:"+course.getCname());
}else{
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t");
};
}
}
}
如果只用单表查询,只能从student表中查询出李晓梅的个人信息,而无法知道她的选课信息,因为选课信息存储在中间表sc中。HQL语句from Student s left join s.course c where s.sname='李晓梅'检索出了李晓梅的选课信息。
在HQL中使用left outer join关键字进行左外连接,outer关键字可以省略。
s.course是Student对象中的一个属性,用来存储Student对象的选课信息。在执行查询时,将根据Student.hbm.xml中的配置生成SQL语句,并检索信息。
查询的结果返回一个Object[]数组,数组的第0个元素是Student对象,第1个元素是与Object[0]中对应的学生所选课的Course对象。
HQLLeftOuterJoinQuery类在执行过程中生成的左外连接的SQL语句如下。
Hibernate:
select
student0_.id as id1_0_,
course2_.id as id4_1_,
student0_.Sno as Sno1_0_,
student0_.Sname as Sname1_0_,
student0_.Sdept as Sdept1_0_,
student0_.Sage as Sage1_0_,
student0_.Ssex as Ssex1_0_,
student0_.Saddress as Saddress1_0_,
course2_.Cno as Cno4_1_,
course2_.Cname as Cname4_1_,
course2_.Ccredit as Ccredit4_1_
from
joblog.student student0_
left outer join
sc course1_
on student0_.id=course1_.sno
left outer join
joblog.course course2_
on course1_.cno=course2_.id
where
student0_.Sname='李晓梅'
Hibernate:
select
course0_.sno as sno1_,
course0_.cno as cno1_,
course1_.id as id4_0_,
course1_.Cno as Cno4_0_,
course1_.Cname as Cname4_0_,
course1_.Ccredit as Ccredit4_0_
from
sc course0_
left outer join
joblog.course course1_
on course0_.cno=course1_.id
where
course0_.sno=?
程序的查询结果如下。
*********学生信息及其选课信息******************
20040001 李晓梅 课程:数据库
*********学生信息及其选课信息******************
20040001 李晓梅 课程:操作系统
使用如下语句将只返回Student对象。
select s from Student s left join s.course c where s.sname='李晓梅'
如下是只返回Student对象的部分代码。
Session session=HibernateSessionFactory.currentSession();
//HQL查询语句
String hql="select s from Student s left join s.course c where s.sname='李晓梅'";
Query query=session.createQuery(hql); //创建查询
List list=query.list(); //执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println("*********学生信息及其选课信息******************");
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t");
}
左外抓取连接
左外抓取连接指定在Hibernate检索数据时,采用抓取的方式,直接将数据加载到与Student对象关联的course属性中。下面是左外抓取连接的程序。
//HQL查询语句
String hql="select s from Student s left join fetch s.course c where s.sname='李晓梅'";
Query query=session.createQuery(hql); //创建查询
List list=query.list(); //执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println("*********学生信息及其选课信息******************");
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t");
}
左外抓取连接使用left join fetch关键字。
与左外连接不同的是:左外抓取连接query.list()返回的集合中存放Student对象的引用,与之相关联的选课信息存放在course属性中。
右外连接
HQL中使用关键字right outer join右外连接,outer关键字可以省略。右外连接与左外连接类似,不再赘述。
内连接
内连接(Inner Join)是指两个表中指定的关键字相等的值才会出现在结果集中的一种查询方式。HQL中使用关键字inner join进行内连接,下面是使用内连接的程序。
Session session=HibernateSessionFactory.currentSession() //创建Session
String hql="from Student s inner join s.course c"; //HQL查询语句
Query query=session.createQuery(hql); //创建查询
List list=query.list(); //执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Object[] obj=(Object[])it.next();
Student stu=(Student)obj[0];
Course course=(Course)obj[1];
System.out.println("*********学生信息及其选课信息******************");
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t"+"课程:"+course. getCname());
}
HQL中使用inner join进行内连接,内连接只关联并检索那些选了课的学生信息及其选课信息,没有选课的学生不在检索结果中。
可以使用select s from Student s inner join s.course c只返回Student对象。
抓取内连接
抓取内连接与内连接不同之处在于其对象的内存状态不一样。HQL中使用inner join fetch进行抓取内连接,如下程序所示。
Session session=HibernateSessionFactory.currentSession(); //创建Session
String hql="select s from Student s inner join fetch s.course c"; //HQL语句
Query query=session.createQuery(hql); //创建查询
List list=query.list(); //执行查询
Iterator it=list.iterator();
while(it.hasNext()){
Student stu=(Student)it.next();
System.out.println("*********学生信息及其选课信息******************");
System.out.println(stu.getSno()+"\t"+stu.getSname()+"\t");
}
转自
http://ajava.org/readbook/open/jthibernate/11558.html
评论
这个是三个表的:
在映射文件中加入关联信息
在Student.hbm.xml映射配置文件中,加入Student到Course的映射信息。关于如何映射关联关系,将在第8章讲解,读者可暂时按照下面的设置,具体含义等阅读完第八章便可理解。具体代码如下。
<set name="course" table="sc" lazy="false" cascade="save-update">
<key column="sno" />
<many-to-many class="hibernate.ch06.Course" column="cno" />
</set>
那两个表的呢?
相关推荐
在实际开发中,HQL关联查询的应用场景非常广泛,特别是在需要跨多个实体进行数据检索的情况下。例如,在电子商务系统中,我们需要获取用户信息及其相关的订单信息时,就可以利用HQL关联查询来简化这一过程。此外,当...
通常,此类会包含对Hibernate Session的操作,如打开Session,执行HQL查询,处理结果集,然后关闭Session。测试代码可能模拟了用户登录系统(SysUser),并尝试获取该用户所关联的所有数据,比如角色(Role)或者...
在实际开发过程中,我们经常会遇到需要从多个表中获取数据的情况,这时就需要用到连表查询。 #### 1. HBM 映射文件 在提供的内容中,出现了两个HBM映射文件:`TopProductsDeputy.hbm.xml` 和 `TopProducts.hbm.xml...
多表查询在HQL中同样直观。第22行的查询演示了如何从`PhCorrelativeUnit`和`PhCorrelativeUnitFunction`两个表中选取数据,并将结果映射到一个Map对象中,其中键值为别名。第25行的查询展示了如何选择多个表的字段...
Hibernate 支持多种方式来实现多表连接查询,包括 HQL(Hibernate Query Language)和 Criteria 查询。本项目主要关注 Criteria API 的使用,这是一种基于 Java 对象的查询方式,更加灵活且易于理解和维护。 **...
4. **HQL多表查询**: 多表查询涉及到两个或更多表的联合查询。例如,将`PhCorrelativeUnit`和`PhCorrelativeUnitFunction`两个表中的相关数据映射到一个Map中: ```java String hql = "select new map(a.CUId as...
HQL是一种面向对象的查询语言,它的语法结构与SQL类似,但更关注于对象和实体,而不是数据库表和列。HQL允许开发者直接操作Java对象,避免了直接编写SQL语句的麻烦,并且支持跨数据库的移植性。 二、HQL模糊查询...
当需要查询多个属性时,可以在`SELECT`子句中列出多个属性,如: ```java List[]> results = session.createQuery("SELECT user.name, user.age FROM User user").list(); ``` 查询结果将以`Object[]`数组的形式...
### HQL查询及语法详解 #### 一、HQL简介 HQL,全称为Hibernate Query Language,是Hibernate框架提供的一种面向对象的查询语言。它基于SQL标准,但更加强调对象模型,支持Java中的对象关系映射(ORM),能够处理...
在这个示例中,我们首先定义了一个HQL查询字符串,该字符串指定了查询的类(Subject)以及模糊匹配的字段(subname 和 subinfo)。接着,我们通过`session.createQuery()`方法创建了一个`Query`对象,并使用`...
HQL查询 帮助文档
Hibernate 的 HQL 语言提供了强大的查询功能,使得我们可以方便地检索和操作数据,特别是在多对多关系的情况下。 知识点: 1. Hibernate 的 HQL 语言可以用来编写查询语句,以便检索和操作数据。 2. 在多对多关系...
hql查询多个实体类,类之间有外键关系,但是没有外键关联
- 在HQL查询语句的`WHERE`子句中使用子查询。 - 关键字`ALL`, `ANY`/`SOME`, `IN`, `EXISTS`等可以用于子查询。 - **HQL提供的集合操作函数**: - `size()`/`size`: 获取集合中元素的数目。 - `minIndex()`/`...
HQL 中的多表查询使用 FROM 语句,例如:FROM eg.Cat as cat, eg.Dog as dog。多表查询可以使用 JOIN 语句来关联多个表。 3.JOIN 语句 HQL 中的 JOIN 语句用于关联多个表,包括 INNER JOIN、LEFT JOIN、RIGHT JOIN...
这里的关键点在于使用`createQuery`方法创建了一个HQL查询对象,并通过`setString`方法设置参数值,最后通过`list`方法执行查询并获取结果列表。 #### 三、分页查询 分页查询在处理大量数据时非常有用,可以有效地...