ネストしたオブジェクトのマッピングする #MyBatis

MyBatisでネストしたオブジェクトマッピングするサンプルあんまり見かけないので、残しておく。

例えばこんなデータを

person

id name address_id
1 yamada 11
2 sato 11

address

id city
11 tokyo

book

id title
21 hoge
22 fuga
23 piyo

person_book

person_id book_id
1 21
1 22
2 23

こんなオブジェクトにマッピングしたい時。。

public class Person {
    private Address address;
    private List<Book> books;

    // アクセサは省略
}

こんな感じになる

<mapper>
    <resultMap id="personMap" type="Person">
         <id column="person_id"/>
         <association property="address" javaType="Address">
           <id property="id" column="address_id"/>
           <result property="city" column="address_city" />
         </association>
         <collection property="books" ofType="Book">
            <id property="id"  column="book_id"/>
            <result property="title" column="book_title"/>
        </collection>
    </resultMap>
    <select id="selectPerson" resultMap="personMap">
        select
            person.id     AS person_id
            address.id    AS address_id,
            address.city  AS address_city,
            book.id       AS book_id,
            book.title    AS book_title
        from
            person person
            inner join
            address address
                on person.address_id = address.id
            inner join
            person_book person_book
                on person.id = person_book.person_id
            inner join
            book book
                on person_book.book_id = book.id
        where
            person.id = 1
    </select>
</mapper>

<id> の指定を忘れない

TooManyResultsExceptionなどが発生してマッピングが期待通りに行かない時は、<id> の指定が漏れていないか確認してみる。

Personクラスではあえてネストしたオブジェクト以外のフィールドを持たせていないが、その場合でも必須になる。(オブジェクトにマッピングする必要がなくても、idは必要)

これはMyBatis側で生成するインスタンスを一意に判別する必要があるからだと思われる。

関連

su-kun1899.hatenablog.com