<collection property="posts" ofType="domain.blog.Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
集合元素和關(guān)聯(lián)元素幾乎是一樣的,它們相似的程度之高,以致于沒有必要再介紹集合元素的相似部分。 所以讓我們來(lái)關(guān)注它們的不同之處吧。
我們來(lái)繼續(xù)上面的示例,一個(gè)博客(Blog)只有一個(gè)作者(Author)。但一個(gè)博客有很多文章(Post)。 在博客類中,這可以用下面的寫法來(lái)表示:
private List<Post> posts;
要像上面這樣,映射嵌套結(jié)果集合到一個(gè) List 中,可以使用集合元素。 和關(guān)聯(lián)元素一樣,我們可以使用嵌套 Select 查詢,或基于連接的嵌套結(jié)果映射集合。
首先,讓我們看看如何使用嵌套 Select 查詢來(lái)為博客加載文章。
<resultMap id="blogResult" type="Blog">
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
</resultMap>
<select id="selectBlog" resultMap="blogResult">
SELECT * FROM BLOG WHERE ID = #{id}
</select>
<select id="selectPostsForBlog" resultType="Post">
SELECT * FROM POST WHERE BLOG_ID = #{id}
</select>
你可能會(huì)立刻注意到幾個(gè)不同,但大部分都和我們上面學(xué)習(xí)過(guò)的關(guān)聯(lián)元素非常相似。 首先,你會(huì)注意到我們使用的是集合元素。 接下來(lái)你會(huì)注意到有一個(gè)新的 “?ofType?” 屬性。這個(gè)屬性非常重要,它用來(lái)將 ?JavaBean?(或字段)屬性的類型和集合存儲(chǔ)的類型區(qū)分開來(lái)。 所以你可以按照下面這樣來(lái)閱讀映射:
<collection property="posts" javaType="ArrayList" column="id" ofType="Post" select="selectPostsForBlog"/>
讀作: “posts 是一個(gè)存儲(chǔ) Post 的 ArrayList 集合”
在一般情況下,MyBatis 可以推斷 ?javaType ?屬性,因此并不需要填寫。所以很多時(shí)候你可以簡(jiǎn)略成:
<collection property="posts" column="id" ofType="Post" select="selectPostsForBlog"/>
現(xiàn)在你可能已經(jīng)猜到了集合的嵌套結(jié)果映射是怎樣工作的——除了新增的 “?ofType?” 屬性,它和關(guān)聯(lián)的完全相同。
首先, 讓我們看看對(duì)應(yīng)的 SQL 語(yǔ)句:
<select id="selectBlog" resultMap="blogResult">
select
B.id as blog_id,
B.title as blog_title,
B.author_id as blog_author_id,
P.id as post_id,
P.subject as post_subject,
P.body as post_body,
from Blog B
left outer join Post P on B.id = P.blog_id
where B.id = #{id}
</select>
我們?cè)俅芜B接了博客表和文章表,并且為每一列都賦予了一個(gè)有意義的別名,以便映射保持簡(jiǎn)單。 要映射博客里面的文章集合,就這么簡(jiǎn)單:
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post">
<id property="id" column="post_id"/>
<result property="subject" column="post_subject"/>
<result property="body" column="post_body"/>
</collection>
</resultMap>
再提醒一次,要記得上面 id 元素的重要性,如果你不記得了,請(qǐng)閱讀關(guān)聯(lián)部分的相關(guān)部分。
如果你喜歡更詳略的、可重用的結(jié)果映射,你可以使用下面的等價(jià)形式:
<resultMap id="blogResult" type="Blog">
<id property="id" column="blog_id" />
<result property="title" column="blog_title"/>
<collection property="posts" ofType="Post" resultMap="blogPostResult" columnPrefix="post_"/>
</resultMap>
<resultMap id="blogPostResult" type="Post">
<id property="id" column="id"/>
<result property="subject" column="subject"/>
<result property="body" column="body"/>
</resultMap>
像關(guān)聯(lián)元素那樣,我們可以通過(guò)執(zhí)行存儲(chǔ)過(guò)程實(shí)現(xiàn),它會(huì)執(zhí)行兩個(gè)查詢并返回兩個(gè)結(jié)果集,一個(gè)是博客的結(jié)果集,另一個(gè)是文章的結(jié)果集:
SELECT * FROM BLOG WHERE ID = #{id}
SELECT * FROM POST WHERE BLOG_ID = #{id}
在映射語(yǔ)句中,必須通過(guò) ?resultSets ?屬性為每個(gè)結(jié)果集指定一個(gè)名字,多個(gè)名字使用逗號(hào)隔開。
<select id="selectBlog" resultSets="blogs,posts" resultMap="blogResult">
{call getBlogsAndPosts(#{id,jdbcType=INTEGER,mode=IN})}
</select>
我們指定 “posts” 集合將會(huì)使用存儲(chǔ)在 “posts” 結(jié)果集中的數(shù)據(jù)進(jìn)行填充:
<resultMap id="blogResult" type="Blog">
<id property="id" column="id" />
<result property="title" column="title"/>
<collection property="posts" ofType="Post" resultSet="posts" column="id" foreignColumn="blog_id">
<id property="id" column="id"/>
<result property="subject" column="subject"/>
<result property="body" column="body"/>
</collection>
</resultMap>
對(duì)關(guān)聯(lián)或集合的映射,并沒有深度、廣度或組合上的要求。但在映射時(shí)要留意性能問(wèn)題。 在探索最佳實(shí)踐的過(guò)程中,應(yīng)用的單元測(cè)試和性能測(cè)試會(huì)是你的好幫手。 而 MyBatis 的好處在于,可以在不對(duì)你的代碼引入重大變更(如果有)的情況下,允許你之后改變你的想法。
高級(jí)關(guān)聯(lián)和集合映射是一個(gè)深度話題。文檔的介紹只能到此為止。配合少許的實(shí)踐,你會(huì)很快了解全部的用法。
更多建議: