MyBatisにおけるResultMapの詳細な使い方

MyBatisがサポートするJDBCデータ型

MyBatisは以下のJDBCデータ型をサポートしています。jdbcType属性で指定する際は、列挙型の値を大文字で記述する必要があります。

データ型データ型データ型データ型データ型データ型
BITFLOATCHARTIMESTAMPOTHERUNDEFINED
TINYINTREALVARCHARBINARYBLOBNVARCHAR
SMALLINTDOUBLELONGVARCHARVARBINARYCLOBNCHAR
INTEGERNUMERICDATELONGVARBINARYBOOLEANNCLOB
BIGINTDECIMALTIMENULLCURSORARRAY

ResultMapの構成要素

  • constructor: オブジェクトのインスタンス化時に、結果をコンストラクタに注入する。
  • idArg: IDとして扱われる引数。パフォーマンス向上に役立つ。
  • arg: コンストラクタに注入される通常の引数。
  • id: IDとして扱われるプロパティ。パフォーマンス向上に役立つ。
  • result: フィールドまたはJavaBeanプロパティに注入される通常の結果。
  • association: 複雑な関連オブジェクトをマッピングする。
  • collection: 複雑なオブジェクトのコレクションをマッピングする。
  • discriminator: 結果の値に基づいて、使用するResultMapを決定する。

1. 基本のidとresultマッピング

プロパティ名とカラム名のマッピング、データ型の指定を行います。jdbcType属性は前述の表に従い、必ず大文字で指定します。

<id property="identifier" column="user_id"/>
<result property="userName" column="name" jdbcType="VARCHAR"/>

2. コンストラクタを用いたマッピング

コンストラクタ引数の順序に基づいてマッピングを行います。IDプロパティにはプリミティブ型のintではなく、ラッパークラスのIntegerを使用することを推奨します。

Javaクラス例:

public class UserAccount {
    private Integer userId;
    private String accountName;
    private String profile;

    public UserAccount(Integer userId, String accountName, String profile) {
        this.userId = userId;
        this.accountName = accountName;
        this.profile = profile;
    }
}

XMLマッピング例:

<resultMap id="userResultMap" type="UserAccount">
    <constructor>
        <idArg column="user_id" javaType="int"/>
        <arg column="account_name" javaType="String"/>
        <arg column="profile" javaType="String"/>
    </constructor>
</resultMap>

コンストラクタ引数の名前でマッピングすることも可能です。その場合、順序は影響しません。以下の2つの方法があります。

方法1: @Paramアノテーションの使用

public UserAccount(@Param("userId") Integer userId,
                   @Param("accountName") String accountName,
                   @Param("profile") String profile) {
    this.userId = userId;
    this.accountName = accountName;
    this.profile = profile;
}
<resultMap id="userResultMap" type="UserAccount">
    <constructor>
        <idArg column="user_id" javaType="int" name="userId"/>
        <arg column="profile" javaType="String" name="profile"/>
        <arg column="account_name" javaType="String" name="accountName"/>
    </constructor>
</resultMap>

方法2: コンパイル時の-parametersオプションとMyBatis設定

Java 8でコンパイル時に-parametersオプションを指定し、MyBatisの設定でuseActualParamNameを有効にします(デフォルトで有効)。

<settings>
    <setting name="useActualParamName" value="true"/>
</settings>

3. 関連オブジェクトのマッピング(association)

使用するエンティティ:

public class Article {
    private int articleId;
    private String heading;
    private String textBody;
    protected Writer writer;
}

public class Writer {
    protected int writerId;
    protected String writerName;
}

ネストされたクエリによる方法

<resultMap id="articleResultMap" type="Article">
    <constructor>
        <idArg column="article_id" javaType="int" name="articleId"/>
        <arg column="heading" javaType="String" name="heading"/>
        <arg column="text_body" javaType="String" name="textBody"/>
    </constructor>
    <association property="writer" column="writer_id" javaType="Writer" select="fetchWriter"/>
</resultMap>

<select id="fetchArticle" resultMap="articleResultMap">
    SELECT article_id, heading, text_body, writer_id FROM article WHERE article_id = #{id}
</select>

<select id="fetchWriter" resultType="Writer">
    SELECT writer_id, writer_name FROM writer WHERE writer_id = #{id}
</select>

ネストされた結果による方法

<resultMap id="articleResultMap" type="Article">
    <constructor>
        <idArg column="article_id" javaType="int" name="articleId"/>
        <arg column="heading" javaType="String" name="heading"/>
        <arg column="text_body" javaType="String" name="textBody"/>
    </constructor>
    <association property="writer" javaType="Writer">
        <id property="writerId" column="writer_id"/>
        <result property="writerName" column="writer_name"/>
    </association>
</resultMap>

<select id="fetchArticle" resultMap="articleResultMap">
    SELECT a.article_id, a.heading, a.text_body, a.writer_id, w.writer_name
    FROM article a
    LEFT OUTER JOIN writer w ON a.writer_id = w.writer_id
    WHERE a.article_id = #{id}
</select>

外部ResultMapを参照する方法

<resultMap id="writerResultMap" type="Writer">
    <id property="writerId" column="writer_id"/>
    <result property="writerName" column="writer_name"/>
</resultMap>

<resultMap id="articleResultMap" type="Article">
    <constructor>
        <idArg column="article_id" javaType="int" name="articleId"/>
        <arg column="heading" javaType="String" name="heading"/>
        <arg column="text_body" javaType="String" name="textBody"/>
    </constructor>
    <association property="writer" javaType="Writer" resultMap="writerResultMap"/>
</resultMap>

4. コレクションのマッピング(collection)

使用するエンティティ:

public class Article {
    private int articleId;
    private String heading;
    private String textBody;
    protected Writer writer;
    protected List<Comment> comments;
}

public class Comment {
    protected int commentId;
    protected String commentText;
    protected String detail;
}

ネストされたクエリによる方法

<resultMap id="articleResultMap" type="Article">
    <constructor>
        <idArg column="article_id" javaType="int" name="articleId"/>
        <arg column="heading" javaType="String" name="heading"/>
        <arg column="text_body" javaType="String" name="textBody"/>
    </constructor>
    <association property="writer" javaType="Writer" column="writer_id" select="fetchWriter"/>
    <collection property="comments" column="article_id" ofType="Comment" select="fetchComments"/>
</resultMap>

<select id="fetchComments" resultType="Comment">
    SELECT * FROM comment WHERE article_id = #{id}
</select>

ネストされた結果による方法

<resultMap id="articleResultMap" type="Article">
    <constructor>
        <idArg column="article_id" javaType="int" name="articleId"/>
        <arg column="heading" javaType="String" name="heading"/>
        <arg column="text_body" javaType="String" name="textBody"/>
    </constructor>
    <association property="writer" javaType="Writer">
        <id property="writerId" column="writer_id"/>
        <result property="writerName" column="writer_name"/>
    </association>
    <collection property="comments" ofType="Comment">
        <id property="commentId" column="comment_id"/>
        <result property="commentText" column="comment_text"/>
        <result property="detail" column="detail"/>
    </collection>
</resultMap>

<select id="fetchArticle" resultMap="articleResultMap">
    SELECT a.article_id, a.heading, a.text_body,
           w.writer_id, w.writer_name,
           c.comment_id, c.comment_text, c.detail
    FROM article a
    LEFT OUTER JOIN writer w ON a.writer_id = w.writer_id
    LEFT OUTER JOIN comment c ON c.article_id = a.article_id
    WHERE a.article_id = #{id}
</select>

5. 識別子を用いたマッピング(discriminator)

使用するエンティティ:

public class Post {
    protected int postId;
    protected String postTitle;
    // getters and setters
}

public class TextPost extends Post {
    protected String postContent;
}

public class ImagePost extends Post {
    protected String imagePath;
}

簡潔な定義方法

<resultMap id="postResultMap" type="Post">
    <id property="postId" column="post_id"/>
    <result property="postTitle" column="title"/>
    <discriminator javaType="int" column="post_type">
        <case value="1" resultType="TextPost">
            <result property="postContent" column="content"/>
        </case>
        <case value="2" resultType="ImagePost">
            <result property="imagePath" column="path"/>
        </case>
    </discriminator>
</resultMap>

外部ResultMapを参照する方法

<resultMap id="textPostResultMap" type="TextPost">
    <result property="postContent" column="content"/>
</resultMap>

<resultMap id="imagePostResultMap" type="ImagePost">
    <result property="imagePath" column="path"/>
</resultMap>

<resultMap id="postResultMap" type="Post">
    <id property="postId" column="post_id"/>
    <result property="postTitle" column="title"/>
    <discriminator javaType="int" column="post_type">
        <case value="1" resultMap="textPostResultMap"/>
        <case value="2" resultMap="imagePostResultMap"/>
    </discriminator>
</resultMap>

タグ: MyBatis ORM ResultMap データベースマッピング XML設定

5月13日 17:23 投稿