mybatis中的級聯關係中的鑑別器(discriminator、case、result)

     

      鑑別器:有時一個單獨的數據庫查詢也許返回很多不同(但是希望有些關聯)數據類型的結果集。鑑別器元素就是被設計來處理這個情況的,還有包括類的繼承層次結構。

      說白一點就是有時候我們想把相同類型的東西放在同一個表中進行查詢,比如我們想把狗和貓放在同一個表中,但是貓和狗有不同的特點,但是我們就想把他們放在一個表中,因爲他們都屬於寵物。爲了從表中查出來時對它們進行區分,也就是說,我在做查詢時我不會說在一個表中我去寫多個查詢方法手動的去指定我想要的那些屬性作爲返回,而是將屬性都進行查詢,讓它自動去區分,向狗的對象或貓的對象進行屬性值的填裝,向我們返回狗的對象還是貓的對象。這種條件下就會用到鑑別器來鑑別到底是狗還是貓,同時要引入繼承的概念,貓和狗都屬於寵物,所以我們在做查詢時,只是去查詢這個寵物,具體查出來是什麼我不管,讓鑑別器去做決定,到底是狗還是貓。

 

下面我們就以貓和狗的例子進行說明

 

父類(寵物類)

首先貓和狗都屬於寵物,所以我們需要一個寵物類

private Integer id;
private String petName;

可以看到寵物有兩個屬性,這是貓和狗都具有的相同屬性,也就是id和名字

 

子類(貓類,繼承寵物類)

private int fish;

可以看到貓類除了繼承自寵物類的屬性外,還有一個fish屬性,這表示的是貓擁有魚的數量,貓喜歡吃魚嘛。

 

子類(狗類,繼承寵物類)

private Integer bone;

可以看到狗類除了繼承自寵物類的屬性外,還有一個bone屬性,這表示的是狗擁有骨頭的數量,狗喜歡骨頭嘛。

 

寵物表(t_pet)創建

從上面的類中我們就可以看到貓和狗都擁有不同的屬性,如何在一個表中進行查詢呢,那麼我們來看下錶(t_pet)的結構:

<!-- pet_type:0代表狗,1代表貓 -->
id,pet_name,pet_type,bone,fish

首先我們建立的是一個寵物表,因爲這個表就包含了它的子類也就是貓和狗的所有屬性。可以看到其中有一個pet_type的字段,這個字段就是用來區分到底是狗還是貓的,鑑別器就是通過這個類型字段來進行裝配的。

 

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

首先我們來寫一個新增狗的方法吧,讓大家瞭解怎樣在插入數據的時候區分:

void addDogBean(@Param("d") DogBean dog);
<insert id="addDogBean" useGeneratedKeys="true" keyProperty="d.id">
	insert into t_pet (pet_name,pet_type,bone) values(#{d.petName},'0',#{d.bone})
</insert>

可以看到我們在做插入狗數據的時候,用狗對象將值傳下來,在底層將pet_type進行了賦值,這樣在表中做查詢時就可以通過這個來進行貓和狗的區分了。

 

如果我們要查詢狗對象呢,怎麼辦呢,很簡單,因爲我們已經知道了要查詢狗對象,所以不需要鑑別器啊,根據pet_type就能夠找出來狗啊,所以這樣寫:

List<DogBean> findAllDogBean();
<select id="findAllDogBean" resultType="DogBean">
	select id,pet_name as petName,bone from t_pet where pet_type = '0';	
</select>

從這裏看出,在我們知道具體要查詢什麼的時候,我們可以直接用類型pet_type字段就可以區分查詢出我們想要的數據。

但是有一種情況,我們就不能這樣了,我想要把狗和貓一起查詢出來呢,你就不可能用一個對象去把不同對象的數據接收了吧,比如你不能用狗對象去接收貓對象,所以這時候鑑別器就出來了。

 

鑑別器的使用(<discriminator>---<case>標籤)

在我們沒做指定查詢具體對象的時候,想把不同類型的數據都查出來的時候,這時候我們就要用到鑑別器來進行不同對象的裝配了。因爲單一對象不能接收其他對象的數據。

下面假設我們把狗和貓都查詢出來:

List<PetBean> findAllPetBean();
<resultMap type="PetBean" id="petMap">
	<!-- 公共的 -->
	<id property="id" column="id" javaType="int"/>
	<result property="petName" column="pet_name" javaType="string"/>
		
	<!-- 通過鑑別器,識別(狗|貓)數據 -->
	<discriminator column="pet_type" javaType="int">
		<case value="0" resultType="DogBean">
			<result property="bone" column="bone" javaType="int"/>
		</case>
		<case value="1" resultType="CatBean">
			<result property="fish" column="fish" javaType="int"/>
		</case>
	</discriminator>
	
</resultMap>

<!-- 查詢所有的貓和狗的數據 -->
<select id="findAllPetBean" resultMap="petMap">
	select id,pet_name,pet_type,bone,fish from t_pet;	
</select>

<discriminator>標籤表示的就是開啓鑑別器,其中的column表示對應的是sql語句中from前面的哪個字段,javaType表示對應的java中的什麼類型

<case>標籤從字面意思就可以看出是分析不同的情況,其中的value表示的是對應的該字段的值,resultType表示我要返回的對象類型

<result>標籤標識我要返回的對象中的屬性和表中字段的映射關係,其中property表示java對象的屬性,column表示表中對應的字段,javaType表示該屬性的java類型。

 

可以看到我們在做結果集映射的時候用的是父類寵物類的引用,因爲父類引用可以指向子類對象的實例,這是Java基礎的內容。在開啓鑑別器後它就會根據具體情況產生對應的實例對象了。

可以看到我們在接口中用了List<PetBean>來接受不同對象的具體實例,父類可以指向子類對象實例,這已經說過了。所以我們在接收到了所有數據之後我們就可以利用循環來判斷裏面具體的數據,再強轉成具體對象,就可以調取對象裏面的數據了啊。比如:

List<Pet> pets = petServiceImpl.findAllPetBean();
for (Pet pet : pets) {
	if (pet instanceof Dog) {
		Dog dog = (Dog) pet;
				
	}else {
		Cat cat = (Cat) pet;			
	}
}

鑑別器的用法就介紹完了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章