1. 程式人生 > >[MyBatis原始碼分析系列] Discriminator

[MyBatis原始碼分析系列] Discriminator

Discriminator

簡介

鑑別器

<discriminator javaType="int" column="draft">
  <case value="1" resultType="DraftPost"/>
</discriminator>

有時一個單獨的資料庫查詢也許返回很多不同(但是希望有些關聯)資料型別的結果集。鑑別器元素就是被設計來處理這個情況的,還有包括類的繼承層次結構。鑑別器非常容易理解,因為它的表現很像Java語言中的switch語句。

定義鑑別器指定了 column 和 javaType 屬性。 列是 MyBatis 查詢比較值的地方。 JavaType 是需要被用來保證等價測試的合適型別(儘管字串在很多情形下都會有用)。比如:

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property
="color" column="color"/>
<discriminator javaType="int" column="vehicle_type"> <case value="1" resultMap="carResult"/> <case value="2" resultMap="truckResult"/> <case value="3" resultMap="vanResult"/> <case value="4" resultMap="suvResult"/> </discriminator
>
</resultMap>

在這個示例中, MyBatis 會從結果集中得到每條記錄, 然後比較它的 vehicle 型別的值。 如果它匹配任何一個鑑別器的例項,那麼就使用這個例項指定的結果對映。換句話說,這樣 做完全是剩餘的結果對映被忽略(除非它被擴充套件,這在第二個示例中討論) 。如果沒有任何 一個例項相匹配,那麼 MyBatis 僅僅使用鑑別器塊外定義的結果對映。所以,如果 carResult 按如下宣告:

<resultMap id="carResult" type="Car">
  <result property="doorCount" column="door_count" />
</resultMap>

那麼只有 doorCount 屬性會被載入。這步完成後完整地允許鑑別器例項的獨立組,儘管 和父結果對映可能沒有什麼關係。這種情況下,我們當然知道 cars 和 vehicles 之間有關係, 如 Car 是一個 Vehicle 例項。因此,我們想要剩餘的屬性也被載入。我們設定的結果對映的 簡單改變如下。

<resultMap id="carResult" type="Car" extends="vehicleResult">
  <result property="doorCount" column="door_count" />
</resultMap>

現在 vehicleResult 和 carResult 的屬性都會被載入了。

儘管曾經有些人會發現這個外部對映定義會多少有一些令人厭煩之處。 因此還有另外一 種語法來做簡潔的對映風格。比如:

<resultMap id="vehicleResult" type="Vehicle">
  <id property="id" column="id" />
  <result property="vin" column="vin"/>
  <result property="year" column="year"/>
  <result property="make" column="make"/>
  <result property="model" column="model"/>
  <result property="color" column="color"/>
  <discriminator javaType="int" column="vehicle_type">
    <case value="1" resultType="carResult">
      <result property="doorCount" column="door_count" />
    </case>
    <case value="2" resultType="truckResult">
      <result property="boxSize" column="box_size" />
      <result property="extendedCab" column="extended_cab" />
    </case>
    <case value="3" resultType="vanResult">
      <result property="powerSlidingDoor" column="power_sliding_door" />
    </case>
    <case value="4" resultType="suvResult">
      <result property="allWheelDrive" column="all_wheel_drive" />
    </case>
  </discriminator>
</resultMap>

原始碼

public class Discriminator {
	
	private ResultMapping resultMapping;
	private Map<String, String> discriminatorMap;

	Discriminator(){
	}

	public static class Builder {
		private Discriminator discriminator = new Discriminator();

		public Builder(Configuration configuration, ResultMapping resultMapping, Map<String, String> discriminatorMap){
			discriminator.resultMapping = resultMapping;
			discriminator.discriminatorMap = discriminatorMap;
		}

		public Discriminator build(){
			assert discriminator.resultMapping != null;
			assert discriminator.discriminatorMap != null;
			assert !discriminator.discriminatorMap.isEmpty();

			discriminator.discriminatorMap = Collections.unmodifiableMap(discriminator.discriminatorMap);
			return discriminator
		}
	}

	public ResultMapping getResultMapping(){
		return resultMapping;
	}

	public Map<String, String> getDiscriminatorMap(){
		return discriminatorMap;
	}

	public String getMapIdFor(String s){
		return discriminatorMap.get(s);
	}
}