关联的嵌套结果映射

属性描述
resultMap结果映射的 ID,可以将此关联的嵌套结果集映射到一个合适的对象树中。 它可以作为使用额外 select 语句的替代方案。它可以将多表连接操作的结果映射成一个单一的 ResultSet。这样的 ResultSet 有部分数据是重复的。 为了将结果集正确地映射到嵌套的对象树中, MyBatis 允许你“串联”结果映射,以便解决嵌套结果集的问题。使用嵌套结果映射的一个例子在表格以后。
columnPrefix当连接多个表时,你可能会不得不使用列别名来避免在 ResultSet 中产生重复的列名。指定 columnPrefix 列名前缀允许你将带有这些前缀的列映射到一个外部的结果映射中。 详细说明请参考后面的例子。
notNullColumn默认情况下,在至少一个被映射到属性的列不为空时,子对象才会被创建。 你可以在这个属性上指定非空的列来改变默认行为,指定后,Mybatis 将只在这些列中任意一列非空时才创建一个子对象。可以使用逗号分隔来指定多个列。默认值:未设置(unset)。
autoMapping如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。注意,本属性对外部的结果映射无效,所以不能搭配 selectresultMap 元素使用。默认值:未设置(unset)。

之前,你已经看到了一个非常复杂的嵌套关联的例子。 下面的例子则是一个非常简单的例子,用于演示嵌套结果映射如何工作。 现在我们将博客表和作者表连接在一起,而不是执行一个独立的查询语句,就像这样:

  1. <select id="selectBlog" resultMap="blogResult">
  2. select
  3. B.id as blog_id,
  4. B.title as blog_title,
  5. B.author_id as blog_author_id,
  6. A.id as author_id,
  7. A.username as author_username,
  8. A.password as author_password,
  9. A.email as author_email,
  10. A.bio as author_bio
  11. from Blog B left outer join Author A on B.author_id = A.id
  12. where B.id = #{id}
  13. </select>

注意查询中的连接,以及为确保结果能够拥有唯一且清晰的名字,我们设置的别名。 这使得进行映射非常简单。现在我们可以映射这个结果:

  1. <resultMap id="blogResult" type="Blog">
  2. <id property="id" column="blog_id" />
  3. <result property="title" column="blog_title"/>
  4. <association property="author" column="blog_author_id" javaType="Author" resultMap="authorResult"/>
  5. </resultMap>
  6. <resultMap id="authorResult" type="Author">
  7. <id property="id" column="author_id"/>
  8. <result property="username" column="author_username"/>
  9. <result property="password" column="author_password"/>
  10. <result property="email" column="author_email"/>
  11. <result property="bio" column="author_bio"/>
  12. </resultMap>

在上面的例子中,你可以看到,博客(Blog)作者(author)的关联元素委托名为 “authorResult” 的结果映射来加载作者对象的实例。

非常重要: id 元素在嵌套结果映射中扮演着非常重要的角色。你应该总是指定一个或多个可以唯一标识结果的属性。 虽然,即使不指定这个属性,MyBatis 仍然可以工作,但是会产生严重的性能问题。 只需要指定可以唯一标识结果的最少属性。显然,你可以选择主键(复合主键也可以)。

现在,上面的示例使用了外部的结果映射元素来映射关联。这使得 Author 的结果映射可以被重用。 然而,如果你不打算重用它,或者你更喜欢将你所有的结果映射放在一个具有描述性的结果映射元素中。 你可以直接将结果映射作为子元素嵌套在内。这里给出使用这种方式的等效例子:

  1. <resultMap id="blogResult" type="Blog">
  2. <id property="id" column="blog_id" />
  3. <result property="title" column="blog_title"/>
  4. <association property="author" javaType="Author">
  5. <id property="id" column="author_id"/>
  6. <result property="username" column="author_username"/>
  7. <result property="password" column="author_password"/>
  8. <result property="email" column="author_email"/>
  9. <result property="bio" column="author_bio"/>
  10. </association>
  11. </resultMap>

那如果博客(blog)有一个共同作者(co-author)该怎么办?select 语句看起来会是这样的:

  1. <select id="selectBlog" resultMap="blogResult">
  2. select
  3. B.id as blog_id,
  4. B.title as blog_title,
  5. A.id as author_id,
  6. A.username as author_username,
  7. A.password as author_password,
  8. A.email as author_email,
  9. A.bio as author_bio,
  10. CA.id as co_author_id,
  11. CA.username as co_author_username,
  12. CA.password as co_author_password,
  13. CA.email as co_author_email,
  14. CA.bio as co_author_bio
  15. from Blog B
  16. left outer join Author A on B.author_id = A.id
  17. left outer join Author CA on B.co_author_id = CA.id
  18. where B.id = #{id}
  19. </select>

回忆一下,Author 的结果映射定义如下:

  1. <resultMap id="authorResult" type="Author">
  2. <id property="id" column="author_id"/>
  3. <result property="username" column="author_username"/>
  4. <result property="password" column="author_password"/>
  5. <result property="email" column="author_email"/>
  6. <result property="bio" column="author_bio"/>
  7. </resultMap>

由于结果中的列名与结果映射中的列名不同。你需要指定 columnPrefix 以便重复使用该结果映射来映射 co-author 的结果。

  1. <resultMap id="blogResult" type="Blog">
  2. <id property="id" column="blog_id" />
  3. <result property="title" column="blog_title"/>
  4. <association property="author"
  5. resultMap="authorResult" />
  6. <association property="coAuthor"
  7. resultMap="authorResult"
  8. columnPrefix="co_" />
  9. </resultMap>