1. 程式人生 > >HQL的多表查詢 left jon 等 (需要配置一對多)

HQL的多表查詢 left jon 等 (需要配置一對多)

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                物件之間總是有各種各樣的關係,關聯關係是類之間最常見的關係。多表查詢是HQL中的強大功能之一,包括內連線、左連線和右連線等。多表查詢的設定及執行都比較麻煩,在執行本節中的示例時,務必保證每一步都沒有錯誤。 

6.4.1  表之間的關聯關係 
在資料庫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; 


6.4.2  表中的資料 
這一節中用到了3個表的資料,student表和course表的資料如6.1節中圖6-2和6-4所示,但是sc表的內容變為圖6-9所示的資料,其中Sno和Cno儲存的分別是student表和course表中對應的主鍵值。 
圖6-9  本節中所用的表sc中的內容 
6.4.3  修改持久化類 
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無需修改。 
6.4.4 在對映檔案中加入關聯資訊 
在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> 


6.4.5  左外連線 
左外連線(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");         } 


6.4.6  左外抓取連線 
左外抓取連線指定在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屬性中。 

6.4.7  右外連線 
HQL中使用關鍵字right outer join右外連線,outer關鍵字可以省略。右外連線與左外連線類似,不再贅述。 

6.4.8  內連線 
內連線(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物件。 

6.4.9  抓取內連線 
抓取內連線與內連線不同之處在於其物件的記憶體狀態不一樣。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");     } 


     內抓取連線使用inner join fech關鍵字。 
     它與內連線的區別是返回檢索的list中存放的是Student物件的引用,與之相關聯的選課資訊存放在course屬性中。
           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述