MyBatis | Mapping Query Results to Arbitrary Java Objects | Mapping to Different Classes Based on Conditions

This method is mainly used when mapping classes that have an inheritance relationship.

DB table

base_table

id common_value type hoge_value fuga_value piyo_value
1 common1 1 hoge1 fuga1 piyo1
2 common2 2 hoge2 fuga2 piyo2
3 common3 3 hoge3 fuga3 piyo3

Source code

Base.java

package sample.mybatis;

public class Base {
    protected int id;
    protected String commonValue;

    @Override
    public String toString() {
        return "Base [id=" + id + ", commonValue=" + commonValue + "]";
    }
}

Hoge.java

package sample.mybatis;

public class Hoge extends Base {
    private String value;

    @Override
    public String toString() {
        return "Hoge [value=" + value + ", id=" + id + ", commonValue=" + commonValue + "]";
    }
}

Fuga.java

package sample.mybatis;

public class Fuga extends Base {
    private String value;

    @Override
    public String toString() {
        return "Fuga [value=" + value + ", id=" + id + ", commonValue=" + commonValue + "]";
    }
}

sample_mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="sample.mybatis">

  <resultMap type="sample.mybatis.Base" id="baseResultMap">
    <id property="id" column="id" />
    <result property="commonValue" column="common_value" />

    <discriminator javaType="int" column="type">
      <case value="1" resultType="sample.mybatis.Hoge">
        <result property="value" column="hoge_value" />
      </case>
      <case value="2" resultType="sample.mybatis.Fuga">
        <result property="value" column="fuga_value" />
      </case>
    </discriminator>
  </resultMap>

  <select id="selectBase" resultMap="baseResultMap">
    select * from base_table
  </select>
</mapper>

Execution result of selectBase

Hoge [value=hoge1, id=1, commonValue=common1]
Fuga [value=fuga2, id=2, commonValue=common2]
Base [id=3, commonValue=common3]

Explanation

  • By using the <discriminator> tag, you can map to different classes depending on a condition.
    • Specify the column that contains the condition value in the column attribute.
  • The <case> tag defines which mapping is performed for each condition value.
    • In this example, value 1 maps to the Hoge class and value 2 maps to the Fuga class.
  • If the condition value does not exist in a <case> expression, it is mapped to the type specified in the original <resultMap> tag.

Defining mappings externally for each case

Source code

sample_mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="sample.mybatis">

  <resultMap type="sample.mybatis.Base" id="baseResultMap">
    <id property="id" column="id" />
    <result property="commonValue" column="common_value" />

    <discriminator javaType="int" column="type">
      <case value="1" resultMap="hogeResultMap" />
      <case value="2" resultMap="fugaResultMap" />
    </discriminator>
  </resultMap>

  <resultMap type="sample.mybatis.Hoge" id="hogeResultMap">
    <result property="value" column="hoge_value" />
  </resultMap>

  <resultMap type="sample.mybatis.Fuga" id="fugaResultMap">
    <result property="value" column="fuga_value" />
    <result property="commonValue" column="common_value" />
  </resultMap>

  <select id="selectBase" resultMap="baseResultMap">
    select * from base_table
  </select>
</mapper>

Execution result

Hoge [value=hoge1, id=1, commonValue=null]
Fuga [value=fuga2, id=2, commonValue=common2]
Base [id=3, commonValue=common3]

Explanation

  • The definition for each <case> can be extracted into a <resultMap>.
  • However, in that case, columns defined in the common part are not mapped except for <id>, so they must be defined in each individual <resultMap>.
    • hogeResultMap does not define commonValue, so it is null.
  • If redefining common items in each individual <resultMap> is tedious, MyBatis provides the extends attribute.

Inheriting common parts with the extends attribute

sample_mapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="sample.mybatis">

  <resultMap type="sample.mybatis.Base" id="baseResultMap">
    <id property="id" column="id" />
    <result property="commonValue" column="common_value" />

    <discriminator javaType="int" column="type">
      <case value="1" resultMap="hogeResultMap" />
      <case value="2" resultMap="fugaResultMap" />
    </discriminator>
  </resultMap>
                                                           <!-- Inherit baseResultMap with extends. -->
  <resultMap type="sample.mybatis.Hoge" id="hogeResultMap" extends="baseResultMap">
    <result property="value" column="hoge_value" />
  </resultMap>

  <resultMap type="sample.mybatis.Fuga" id="fugaResultMap" extends="baseResultMap">
    <result property="value" column="fuga_value" />
  </resultMap>

  <select id="selectBase" resultMap="baseResultMap">
    select * from base_table
  </select>
</mapper>

Execution result

Hoge [value=hoge1, id=1, commonValue=common1]
Fuga [value=fuga2, id=2, commonValue=common2]
Base [id=3, commonValue=common3]