How to MyBatisで値オブジェクトを持ったクラスへのマッピング


やりたいこと

最近、オブジェクト指向の設計についてお勉強中なのですが、
ドメインオブジェクトを使っているとデータベースの都合のクラスの存在がやっかいに感じ、
データベースから取得した値を直接ドメインオブジェクトの形で受け取れたらなぁと考えていました

自分もまだまだ勉強中なので、1つの解決方法としてMyBatisを使ってみましたが、
データベースから値を取得する時のいい方法があれば教えていただきたいです

環境

  • Java 8
  • Spring boot 2.1.9
  • MyBatis Spring boot starter 2.0.1
  • MySQL 5.7.1

MyBatisでSELECTしてみる

MeetingRoomクラスをMyBatisを使って取得をする

public class MeetingRoom {
    private int id;
    private String name;

    ...
}
@Mapper
public interface MeetingRoomMapper {

    MeetingRoom findById(int roomId);
}
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.spring.tutorial.MeetingRoomMapper">
    <select id="findById" resultType="com.spring.tutorial.MeetingRoom">
        SELECT
            room_id as id,
            room_name as name
        FROM
            meeting_room
        WHERE
            room_id = #{room_id}
    </select>
</mapper>

ってな感じでMapperクラスのfindByIdの戻り値と、MapperファイルのResultTypeにMeetingRoomを指定してあげるとMeetingRoomの形で返してくれます。
また、カラム名とプロパティ名が一致している必要があるので、AS句で指定しています。

値オブジェクトを使う

MeetingRoomのIDをint型からIdクラスへ変更します。

public class MeetingRoom {
    //値オブジェクトに変更
    private Id id;
    private String name;

    ...
}
public class Id {
    private static final int MIN = 1;
    private Integer value;

    Id(int value) {
        if (value < MIN) throw new IllegalArgumentException("不正な値です。 value:" + value);

        this.value = value;
    }

     ...
}

ResultMapを使ってIdクラスとMeetingRoomクラスの設定をします。

    <resultMap id="IdMap" type="com.spring.tutorial.Id" >
        <id property="value" column="room_id" />
    </resultMap>

    <resultMap id="MeetingRoomMap" type="com.spring.tutorial.MeetingRoom">
        <result property="name" column="room_name" />
        <association property="id" resultMap="IdMap"/>
    </resultMap>

    <select id="findById" resultMap="MeetingRoomMap">
        SELECT * FROM meeting_room WHERE room_id = #{room_id}
    </select>

SELECTのResultTypeをResultMapに変更し、MeetingRoomのResultMapを指定します。
ResultMap内でResultMapを使うときはassociationを使います。
同じオブジェクトのプロパティにresultがいる時、associationを下に記述しないとエラーが出るので気をつける

要素タイプ"resultMap"のコンテンツは"(constructor?,id*,result*,association*,collection*,discriminator?)"と一致する必要があります。

まとめ

データベースの都合のクラスを増やさなくていいからMyBatisはいい

参考

現場で役立つシステム設計の原則
mybatis - Mapper XML ファイル