ResultMap
在resultMap的元素是MyBatis中最重要最强大的元素。这就是您可以使用JDBC从ResultSet中检索数据的90%的代码,在某些情况下允许您执行JDBC甚至不支持的操作。事实上,编写复杂语句的连接映射等效代码可能会跨越数千行代码。ResultMap的设计是这样的:简单的语句根本不需要显式的结果映射,而更复杂的语句只需要描述关系是绝对必要的。
您已经看到了没有显式resultMap的简单映射语句的例子。例如:
<select id="selectUsers" resultType="map"> select id, username, hashedPassword from some_table where id = #{id} </select>
这样的语句只会导致所有列自动映射到HashMap的键,如resultType属性所指定。虽然在很多情况下很有用,但HashMap并不是一个很好的领域模型。更有可能的是,您的应用程序将为域模型使用JavaBean或POJO(Plain Old Java Objects)。MyBatis同时支持。考虑下面的JavaBean:
package com.someapp.model; public class User { private int id; private String username; private String hashedPassword; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getHashedPassword() { return hashedPassword; } public void setHashedPassword(String hashedPassword) { this.hashedPassword = hashedPassword; } }
基于JavaBeans规范,上面的类有3个属性:id,username和hashedPassword。这些与select语句中的列名完全匹配。
这样的JavaBean可以像HashMap那样容易地映射到ResultSet。
<select id="selectUsers" resultType="com.someapp.model.User"> select id, username, hashedPassword from some_table where id = #{id} </select>
请记住TypeAliases是你的朋友。使用它们,以便您不必继续输入班级的完全限定路径。例如:
<!-- In Config XML file --> <typeAlias type="com.someapp.model.User" alias="User"/> <!-- In SQL Mapping XML file --> <select id="selectUsers" resultType="User"> select id, username, hashedPassword from some_table where id = #{id} </select>
在这些情况下,MyBatis 在后台自动创建一个ResultMap,以根据名称自动将列映射到JavaBean属性。如果列名不完全匹配,则可以在列名上使用select子句别名(标准SQL功能)以使标签匹配。例如:
<select id="selectUsers" resultType="User"> select user_id as "id", user_name as "userName", hashed_password as "hashedPassword" from some_table where id = #{id} </select>
关于ResultMap的好处是你已经学到了很多关于它们的知识,但是你还没有看到它呢!这些简单的情况不需要比你在这里看到的更多。举例来说,让我们看看最后一个例子看起来像一个外部resultMap,这是解决列名不匹配的另一种方法。
<resultMap id="userResultMap" type="User"> <id property="id" column="user_id" /> <result property="username" column="user_name"/> <result property="password" column="hashed_password"/> </resultMap>
并且引用它的语句使用resultMap属性(注意我们移除了 resultType属性)。例如:
<select id="selectUsers" resultMap="userResultMap"> select user_id, user_name, hashed_password from some_table where id = #{id} </select>
现在只要这个世界总是那么简单。
高级resultMap
在resultMap的元素是MyBatis中最重要最强大的元素。这就是您可以使用JDBC从ResultSet中检索数据的90%的代码,在某些情况下允许您执行JDBC甚至不支持的操作。事实上,编写复杂语句的连接映射等效代码可能会跨越数千行代码。ResultMap的设计是这样的:简单的语句根本不需要显式的结果映射,而更复杂的语句只需要描述关系是绝对必要的。
您已经看到了没有显式resultMap的简单映射语句的例子。例如:
<!-- Very Complex Statement --> <select id="selectBlogDetails" resultMap="detailedBlogResultMap"> select B.id as blog_id, B.title as blog_title, B.author_id as blog_author_id, A.id as author_id, A.username as author_username, A.password as author_password, A.email as author_email, A.bio as author_bio, A.favourite_section as author_favourite_section, P.id as post_id, P.blog_id as post_blog_id, P.author_id as post_author_id, P.created_on as post_created_on, P.section as post_section, P.subject as post_subject, P.draft as draft, P.body as post_body, C.id as comment_id, C.post_id as comment_post_id, C.name as comment_name, C.comment as comment_text, T.id as tag_id, T.name as tag_name from Blog B left outer join Author A on B.author_id = A.id left outer join Post P on B.id = P.blog_id left outer join Comment C on P.id = C.post_id left outer join Post_Tag PT on PT.post_id = P.id left outer join Tag T on PT.tag_id = T.id where B.id = #{id} </select>
这样的语句只会导致所有列自动映射到HashMap的键,如resultType属性所指定。虽然在很多情况下很有用,但HashMap并不是一个很好的领域模型。更有可能的是,您的应用程序将为域模型使用JavaBean或POJO(Plain Old Java Objects)。MyBatis同时支持。考虑下面的JavaBean:
<!-- Very Complex Result Map --> <resultMap id="detailedBlogResultMap" type="Blog"> <constructor> <idArg column="blog_id" javaType="int"/> </constructor> <result property="title" column="blog_title"/> <association property="author" javaType="Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> <result property="password" column="author_password"/> <result property="email" column="author_email"/> <result property="bio" column="author_bio"/> <result property="favouriteSection" column="author_favourite_section"/> </association> <collection property="posts" ofType="Post"> <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> <collection property="tags" ofType="Tag" > <id property="id" column="tag_id"/> </collection> <discriminator javaType="int" column="draft"> <case value="1" resultType="DraftPost"/> </discriminator> </collection> </resultMap>
现在只要这个世界总是那么简单。
resultMap
- constructor构造函数 - 用于在实例化时将结果注入到类的构造函数中
- idArg - ID参数; 标记结果作为ID将有助于提高整体性能
- arg - 注入构造函数的正常结果
- id - 一个ID结果; 标记结果作为ID将有助于提高整体性能
- result - 注入到字段或JavaBean属性中的正常结果
- association - 一个复杂的类型协会; 许多结果将卷入这种类型
- 嵌套的结果映射 - 关联是resultMap本身,或可以引用一个
- collection - 复杂类型的集合
- 嵌套的结果映射 - 集合本身就是resultMap,也可以引用其中的一个
- discriminator - 使用结果值来确定使用 哪个resultMap
- case - 一个案例是基于某种价值的结果图
- 嵌套的结果映射 - 一个案例也是一个结果映射本身,因此可以包含许多这些相同的元素,或者它可以引用一个外部的resultMap。
- case - 一个案例是基于某种价值的结果图
属性 | 描述 |
---|---|
id | 此名称空间中的唯一标识符,可用于引用此结果映射。 |
type | 完全限定的Java类名称或类型别名(请参阅上表中的内置类型别名列表)。 |
autoMapping | 如果存在,MyBatis将启用或禁用此ResultMap的自动映射。该属性重写全局autoMappingBehavior。默认:未设置。 |
最佳实践始终逐步构建ResultMaps。单元测试真的有帮助。如果你试图像上面那样建立一个巨大的resultMap,那么很可能你会弄错了,而且很难一起工作。从简单开始,逐步发展一步。和单元测试!使用框架的缺点是它们有时是一个黑盒子(不管是否是开源的)。确保你达到你想要的行为的最好方法就是编写单元测试。提交错误时也有帮助。