1. 程式人生 > >10.關聯關系查詢

10.關聯關系查詢

避免 及其 family 類型 新聞 情況 .com 兩個 一個

關聯關系查詢

當查詢內容涉及到具有關聯關系的多個表時,就需要使用關聯查詢

根據表與表間的關聯關系的不同,關聯查詢分為四種:

(1)一對一關聯查詢

(2)一對多關聯查詢

(3)多對一關聯查詢

(4)多對多關聯查詢

由於日常工作中最常見的關聯關系是一對多、多對一與多對多,所以這裏就不專門只講

解一對一關聯查詢了,其解決方案與多對一解決方案是相同的。

1.一對多關聯查詢

在查詢一方的時候,同時將其所關聯的多方對象也都查詢出來

A、多表連接查詢方式(一條SQL語句):

 1 <mapper namespace="com.mybatis.dao.CountryDAO" >
 2 <!--
parameterType 可以省略 --> 3 4 <resultMap type="Country" id="countryMapper"> 5 <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 --> 6 <id column="cid" property="cid"/> 7 <result column="cname" property="cname"/> 8 <!--
一對多,一的一方存儲了多的一方,以集合的形式,collection標簽可以幫助我們完成 集合裏面對象的構成 --> 9 <collection property="ministers" ofType="Minister"> 10 <id column="mid" property="mid"/> 11 <result column="mname" property="mname" /> 12 </collection> 13 </resultMap> 14 15
16 <!-- 多表連接查詢方式,這種方式 無法進行延遲加載,多的一方直接跟著 一的一方一起查出來了,會消耗很多資源 --> 17 <select id="selectCountryById" resultMap="countryMapper"> 18 <!-- 查詢出了這四個字段,但是這四個字段是無法直接構成country對象的 ,故使用resultMap,讓其將mid,mname構成ministers,再構成country--> 19 select cid,cname,mid,mname from country,minister where countryId = cid and cid = #{cid} 20 </select> 22 </mapper>

  在映射文件中使用 <collection/>標簽體現出兩個實體對象間的關聯關系。其兩個屬性的意義位:

  property:指定關聯類型,即Country類中的集合類型

  ofType:集合屬性的泛型類型

B、多表單獨查詢方式(多條SQL語句)

多表連接查詢方式是將多張表進行連接,連為一張表後進行查詢。其查詢的本質是一張表。

而多表單獨查詢方式是多張表各自查詢各自的相關內容,需要多張表的聯合數據了,

將主表的查詢結果聯合其它表的查詢結果,封裝為一個對象。

當然,這多個查詢是可以跨越多個映射文件的,即是可以跨越多個 namespace 的。

使用其它 namespace 的查詢時,添加上其所在的 namespace 即可

 1 <mapper namespace="com.mybatis.dao.CountryDAO" >
 2     
 3     <resultMap type="Country" id="countryMapper">
 4         <id column="cid" property="cid"/> 
 5         <result column="cname" property="cname"/>
 6         <!-- 執行到這裏時,會調用 select 屬性中的 SQL,column 作為外鍵參數,cid-->
 7         <collection property="ministers" ofType="Minister" select="selectMinisterByCountry" column="cid">
 8         </collection>
 9     </resultMap>
10     
11     <!-- 使用多表單獨查詢的方式(使用多條SQL語句) 采用這種方式,可以實現延遲加載-->
12     <!-- 由DAO調用,故先執行 selectCountryById ,執行到collection,這時需要 執行 selectMinisterByCountry -->
13     <select id="selectCountryById" resultMap="countryMapper">
14         select cid,cname from country where cid = #{cid}
15     </select>
16     <select id="selectMinisterByCountry" resultType="Minister">
17          select mid,mname from minister where countryId = #{countryId}
18     </select>
19     
20 </mapper>

關聯屬性<collection/>的數據來自於另一個查詢<selectMinisterByCountry/>。

而該查詢<selectMinisterByCountry/>的動態參數 countryId=#{ooo}的值來自於查詢<selectCountryById/>的查詢結果字段 cid

2.多對一關聯查詢

在查詢多方對象的時候,同時將其所關聯的一方對象也查 詢出來。

由於在查詢多方對象時也是一個一個查詢,所以多對一關聯查詢,其實就是一對一關聯查詢

即一對一關聯查詢的實現方式與多對一的實現方式是相同的

 1 <mapper namespace="com.mybatis.dao.MinisterDAO" >
 2 <!-- parameterType 可以省略 -->
 3     
 4     <resultMap type="Minister" id="ministerMapper">
 5     <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 -->
 6         <id column="mid" property="mid"/> 
 7         <result column="mname" property="mname"/>
 8         
 9         <!-- 多對一采用的是 association 來完成關聯屬性的構成 -->
10         <association property="country" javaType="Country">
11             <id column="cid" property="cid"/> 
12             <result column="cname" property="cname"/>
13         </association>
14     </resultMap>
15     
16     
17     <!-- 多表連接查詢方式,這種方式 無法進行延遲加載,多的一方直接跟著 一的一方一起查出來了,會消耗很多資源 -->
18     <select id="selectMinisterById" resultMap="ministerMapper">
19         select mid,mname,cid,cname from minister,country where mid = #{mid} and countryId = cid 
20     </select>
21     
22 </mapper>

註意:在映射文件中使用 <association/> 標簽體現出兩個實體對象間的關聯關系

  property:指定關聯屬性,即Minister類中的 country屬性

  javaType:關聯屬性的類型

多表單獨查詢的方式

 1 <mapper namespace="com.mybatis.dao.MinisterDAO" >
 2 <!-- parameterType 可以省略 -->
 3     
 4     <resultMap type="Minister" id="ministerMapper">
 5     <!-- 和解決字段名和屬性名不相同的問題 不同,在這裏,就算屬性名和數據庫中的字段名一致,也要寫出來,不會主動幫你填入的 -->
 6         <id column="mid" property="mid"/> 
 7         <result column="mname" property="mname"/>
 8         
 9         <!-- 多對一采用的是 association 來完成關聯屬性的構成 -->
10         <association property="country" javaType="Country" select="selectCountryById" column="countryId">
11             <id column="cid" property="cid"/> 
12             <result column="cname" property="cname"/>
13         </association>
14     </resultMap>
15     
16     
17     <!-- 使用多表單獨查詢的方式(使用多條SQL語句) 采用這種方式,可以實現延遲加載-->
18     <select id="selectMinisterById" resultMap="ministerMapper">
19         select mid,mname,countryId from minister where mid = #{mid}
20     </select>
21     
22     <select id="selectCountryById" resultType="Country">
23         select cid,cname from country where cid = #{countryId}
24     </select>
25     
26 </mapper>

3.自關聯查詢

所謂自關聯是指,自己即充當一方,又充當多方,是 1:n 或 n:1 的變型

例如,對於新聞欄目 NewsColumn,可以充當一方,即父欄目,也可以充當多方,即子欄目。而反映到 DB 表中,只有一張表,這張表中具有一個外鍵,用於表示該欄目的父欄目。一級欄目沒有父欄 目,所以可以將其外鍵值設為 0,而子欄目則具有外鍵值。

為了便於理解,將自關聯分為兩種情況來講解。一種是當作 1:n 講解,即當前類作為一 方,其包含多方的集合域屬性。一種是當作 n:1 講解,即當前類作為多方,其包含一方的域 屬性。

下面以新聞欄目為例進行講解。由於 Column 是 DBMS 中的關鍵字,為了避免誤解,將 新聞欄目實體類定義為 NewsLabel。

技術分享

以一對多方式處理:

   以一對多方式處理,即一方可以看到多方。該處理方式的引用場景比較多,例如在頁面上點擊父欄目,顯示出其子欄目

A、查詢指定欄目的所有子孫欄目:

 1 <mapper namespace="com.mybatis.dao.NewsLabelDAO" >
 2 
 3 <!-- 自關聯查詢 -->    
 4     
 5     <resultMap type="NewsLabel" id="newsLabelMapper">
 6         <id property="id" column="id"/>
 7         <result property="name" column="name"/>
 8         <!-- pid動態參數值 來自上一次查詢的結果的 id 值 -->
 9         <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParentId" column="id"/>
10 
11     </resultMap>
12     
13     <!-- select 語句的遞歸調用  -->
14     <!-- 過程:1.先查到 3,4是2 的 子元素 
15                2.深度優先,從3開始下手,在構造3的chirldren屬性時,需要去查3下面是否有子元素(因為collection中 使用的select 語句是selectChildrenByParentId)
16                     這就構成了遞歸,如果3下面有子元素,則再遞歸著去查這個子元素下面是否還要子元素
17                    
18     -->
19     <select id="selectChildrenByParentId" resultMap="newsLabelMapper">
20         select id,name from newslabel where pid = #{pid}
21     </select>
22     
23     
24 </mapper>

B、查詢指定欄目及其所有子孫欄目:

這裏的查詢結果,即要包含指定 id 的當前欄目,還包含其所有輩份的孫子欄目。

即給 出的 id 實際為當前要查詢的欄目的 id

 1 <!-- 自關聯查詢 -->    
 2     <resultMap type="NewsLabel" id="newsLabelMapper">
 3         <id property="id" column="id"/>
 4         <result property="name" column="name"/>
 5         <!-- pid動態參數值 來自上一次查詢的結果的 id 值 -->
 6         <collection property="chirldren" ofType="NewsLabel" select="selectChildrenByParent" column="id"/>
 7 
 8     </resultMap>
 9     
10     <!-- 1.先根據查出 查出對應的 NewsLabel -->
11     <select id="selectNewsLabelById" resultMap="newsLabelMapper">
12         select id,name from newslabel where id = #{id}
13     </select>
14     
15     <!-- 2.再根據前一次出的id 作為 pid,查詢這個id 下所有的子元素 -->
16     <select id="selectChildrenByParent" resultMap="newsLabelMapper">
17         select id,name from newslabel where pid = #{id}
18     </select>
19     
20     
21     
22     
23 </mapper>

以多對一方式處理:

  以多對一方式處理,即多方可以看到一方

 1 <!-- 自關聯查詢 -->    
 2     
 3     <resultMap type="NewsLabel" id="newsLabelMapper">
 4         <id property="id" column="id"/>
 5         <result property="name" column="name"/>
 6         <!-- pid動態參數值 來自上一次查詢的結果的 id 值 -->
 7         <association property="parent" javaType="NewsLabel" select="selectParentByParentId" column="pid"/>
 8 
 9     </resultMap>
10     
11     <select id="selectParentByParentId" resultMap="newsLabelMapper">
12         select id,name,pid from newslabel where id = #{pid}
13     </select>
14     
15     
16 </mapper>

4.多對多關聯查詢

什麽是多對多關聯關系?一個學生可以選多門課程,而一門課程可以由多個學生選。這就是典型的多對多關系關系。

所以,所謂多對多關系,其實是由兩個互反的一對多關系組成。

一般情況下,多對多關系都會通過一個中間表來建立,例如選課表。

多對多關聯關系也是通過映射文件<resultMap/>的<cooection/>體現的

但是,需要註意的是SQL語句中是對三張表的連接查詢

 1 <!-- 多對多查詢 -->    
 2     
 3     <resultMap type="Student" id="studentMapper">
 4         <id property="sid" column="sid"/>
 5         <result property="sname" column="sname"/>
 6         <collection property="courses" ofType="Course" >
 7             <id property="cid" column="cid"/>
 8             <result property="cname" column="cname"/>
 9         </collection>
10 
11     </resultMap>
12     
13     <select id="selectStudentById" resultMap="studentMapper">
14         select sid,sname,cid,cname from student,course,middle where sid = studentId and cid = courseId and sid = #{sid}
15     </select>

10.關聯關系查詢