MyBatisのresultMap内にタグを記述するルール

# 概要
MyBatisの中で最も強力な機能の一つにresultMapがあります。
resultMapはSQLの結果をJavaのクラスにマッピングする際に利用され、実に柔軟でかつ手軽に利用できます。
また、resultMapは`<resultMap>`内にMyBatis既定のタグを構造的に記述することで、複雑なJavaオブジェクトでもマッピングを可能にしてくれます。ただし記述には一定のルールがあるため、フレームワーク特有のルールに従った記述が必要です。

**この投稿では、いくつかあるMyBatisの記述ルールの内、記述順序について説明します。**



※当記事は.xml形式のMapperを記述すること想定してます。

# resultMap内の記述ルール
必ず以下の順序で記述する必要があります。


1. `<constructor>`
1. `<id>` もしくは `<idArg>`
1. `<result>`
1. `<association>`
1. `<collection>`
1. `<discriminator>`


# 例
例えば、次の場合はエラーとなります。
なぜなら、`<id>`と`<result>`の記述順序が逆であるためです。

```:NGパターン
<resultMap id="detailedBlogResultMap" type="Blog">
  <result property="username" column="author_username"/>
  <id property="id" column="author_id"/>
</resultMap>
```

この場合、次のように修正する必要があります。
`<id>`と`<result>`の順序を入れ替えます。

```:修正後
<resultMap id="detailedBlogResultMap" type="Blog">
  <id property="id" column="author_id"/>
  <result property="username" column="author_username"/>
</resultMap>
```



# エラー
記述順序が逆である場合は、次のようなエラーが投げられます。
このエラーが確認された場合は、MyBatisの<resultMap>内の記述順序を疑ってみて下さい。

```:例外メッセージ
Caused by: org.xml.sax.SAXParseException: The content of element type "resultMap" must match "(constructor?,id*,result*,association*,collection*,discriminator?)".
```



# その他の例
続けて、NGと修正のパターンをいくつか例示します。
本質的には上記で説明した内容と重複しますが、いくつかのパターンを用意しましたので実装時に参考になれば幸いです。


### 例1
`<collection>`と`<association>`の順序が逆なためNG


```:NGパターン
<resultMap id="detailedBlogResultMap" type="Blog">
  <idArg column="blog_id" javaType="int"/>
  <result property="title" column="blog_title"/>
  <collection property="tags" ofType="Tag" >
    <id property="id" column="tag_id"/>
  </collection>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
  </association>
</resultMap>
```


```:修正後
<resultMap id="detailedBlogResultMap" type="Blog">
  <idArg column="blog_id" javaType="int"/>
  <result property="title" column="blog_title"/>
-   <collection property="tags" ofType="Tag" >
-     <id property="id" column="tag_id"/>
-   </collection>
  <association property="author" javaType="Author">
    <id property="id" column="author_id"/>
    <result property="username" column="author_username"/>
  </association>
+   <collection property="tags" ofType="Tag" >
+     <id property="id" column="tag_id"/>
+   </collection>
</resultMap>
```


### 例2
`<collection>`内の`<association>`が`<id>`と`<result>`より上にあるためNG


```:NGパターン
<resultMap id="detailedBlogResultMap" type="Blog">
  <id property="id" column="author_id"/>
  <collection property="posts" ofType="Post">
    <association property="author" javaType="Author"/>
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>
```


```:修正後
<resultMap id="detailedBlogResultMap" type="Blog">
  <id property="id" column="author_id"/>
  <collection property="posts" ofType="Post">
-     <association property="author" javaType="Author"/>
    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>
+     <association property="author" javaType="Author"/>
    <collection property="comments" ofType="Comment">
      <id property="id" column="comment_id"/>
    </collection>
    <discriminator javaType="int" column="draft">
      <case value="1" resultType="DraftPost"/>
    </discriminator>
  </collection>
</resultMap>
```



# 参考資料
- MyBatis – MyBatis 3 | Mapper XML ファイル https://mybatis.org/mybatis-3/ja/sqlmap-xml.html