MyBatisでresultTypeのオブジェクトの変数にオブジェクト(ネストしたオブジェクト)がある場合に取得結果をmappingする

### 概要
本記事では、MyBatisでmapperの戻り値のクラスの変数に自身が作成したクラス型の変数が含まれる場合でのmapperの記述方法を説明します。

### 環境
- OS: macOS Mojave
- Spring boot: 2.1.4.RELEASE
- MyBatis: 2.0.1

### 前提
- 今回実現したいこと  
以下のように、インスタンス変数に自身で作成したクラス型の変数を持っているクラスのオブジェクトにMyBatisで取得した結果を入れる。

今回は、Member型のListとUrl型をインスタンス変数にもつTeamクラスを例に説明します。

```java:Team.java
package com.webapp.sample;

public class Team {
    private String name;
    private Url siteUrl;
    private List<Member> members;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    public void setSiteUrl(Url siteUrl) {
        this.siteUrl= siteUrl;
    }
    public Url getSiteUrl() {
        return this.siteUrl;
    }
    public void setMembers(List<Member> members) {
        this.members = members;
    }
    public List<Member> getMembers() {
        return this.members;
    }
}
```

このTeamクラスはインスタンス変数として、Url型の変数とList\<Member>型の変数を持っています。UrlクラスとMemberクラスは以下の通りとします。

```java:Url.java
package com.webapp.sample;

public class Url {
    private String address;
    public void setAddress(String address) {
        this.address = address;
    }
    public String getAddress() {
        return this.address;
    }
}
```

```java:Member.java
package com.webapp.sample;

public class Member {
    private String name;
    private int age;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return this.name;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getAge() {
        return this.age;
    }
}
```
上記のように、MyBatisで取得した値を格納するオブジェクトの中にさらにオブジェクトがある場合、SQL文で取得したカラムの値を自動的にオブジェクトにmappingできないので、mapperに設定を記述する必要があります。

### Mapperの記述
例として、TEAMテーブルとMEMBERテーブルからデータを取得し、Teamクラスのオブジェクトに値を入れる処理を書きます。テーブルのカラムは以下の通りです。

TEAMテーブル

|id |name|url|
|---|----|---|

MEMBERテーブル

|id |name|age|team_id|
|---|----|---|-------|

MEMBERテーブルのteam_idは外部キーでTEAMテーブルのidを参照しています。

mapperは以下のように書きます。


```xml:TeamMapper.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="com.webapp.sample.mapper.CategoryMapper">
    <select id="findAllTeams" resultMap="TeamMap">
        SELECT
            id,
            t.name as t_name,
            t.url as t_url
        FROM
            team t
    </select>

    <resultMap id="TeamMap" type="com.webapp.sample.Team">
        <id column="id"></id>
        <result column="t_name" property="name"></result>
        <association property="url" javaType="com.webapp.sample.Url">
            <result column="t_url" property="address"></result>
        </association>
        <collection property="members" column="id" javaType="ArrayList" select="findMembers">
        </collection>
    </resultMap>

    <select id="findMembers" resultMap="MemberMap">
        SELECT
            m.name as m_name,
            m.age as m_age
        FROM
            member m
        WHERE
            m.id = #{id}
    </select>

    <resultMap id="MemberMap" type="com.webapp.sample.Member">
        <id column="id"></id>
        <result column="m_name" property="name"></result>
        <result column="m_age" property="age"></result>
    </resultMap>

</mapper>
```
### タグ解説
このxmlファイルは、resultMapタグとselectタグの大きく2つに分かれています。resultMapタグの中にテーブルのカラムとオブジェクトとのmappingを定義し、selectタグの中にSQL文を書きます。
さらに、Memberクラスのリストを取得するために、TEAMを取得するSQLとMEMBERを取得するSQLに分けています。

#### selectタグ
selectタグには、select文を記述します。select文で取得するオブジェクトがネストしていない場合は、取得した値を入れるクラスをresultType属性で指定していましたが、今回のようにオブジェクトがネストしている場合は、resultType属性の代わりに、resultMap属性に、これから定義するresultMapタグのidを記述します。これを書くことによって、resultMapタグ内に書いた定義通りに取得した値がmappingされます。 
　さらに、今回の例ではTeamクラスのメンバ変数にMemberクラスのListがあるため、select文をTEAMテーブルの項目を取得するselect文とMEMBERテーブルの項目を取得するselect文に分けます。
#### resultMapタグ
resultMapにはid属性とtype属性があります。id属性にはこの定義を識別するための文字列を記述します。type属性には取得した値を入れるクラスをpackage名から記述します。
#### resultタグ
resultタグは、個々の変数に対応しています。column属性にselect文で取得した時のカラム名称を書き、property属性にクラスでの変数名を書きます。つまり、columnとpropertyが対応づいています。
#### associationタグ
associationタグは、resultMapタグのtype属性で指定したクラスの変数の中にオブジェクトがあった場合に使用します。今回の例ではTeamクラス内のUrl型のインスタンス変数に対応しています。property属性には、Teamクラスでの変数名を書き、javaTypeには、型を書きます。Url型の変数のaddressに対してはresultタグで対応づけています。
#### collectionタグ
collectionタグは、List型などに対して使用します。先ほどと同様にproperty属性には、変数名を書きます。column属性には、取得するリスト(ここでいうmembers)を検索する際のキーを書きます。このキーが下のselect文にバインドされます。例ではTEAMテーブルのidがこれに該当します。javaTypeには型を書きます。select属性には、このリストを取得するために使用するSQL文のidを書きます。例では、下のselectタグのid属性を書いています。