<!-- 非常复杂的语句 --> <select id="selectBlogDetails" parameterType="int" 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>
......
<!-- 非常复杂的结果映射 --> <resultMap id="detailedBlogResultMap" type="Blog"> <constructor> <idArg column="blog_id" javaType="int"/> </constructor> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" 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" column="post_author_id" javaType="Author"/> <collection property="comments" column="post_id" ofType=" Comment"> <id property="id" column="comment_id"/> </collection> <collection property="tags" column="post_id" ofType=" Tag" > <id property="id" column="tag_id"/> </collection> <discriminator javaType="int" column="draft"> <case value="1" resultType="DraftPost"/> </discriminator> </collection> </resultMap>
id,result
<resultMap> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> </resultMap>这些是结果映射最基本内容。id和result都映射一个单独列的值到简单数据类型(字符串,整型,双精度浮点数,日期等)的单独属性或字段。
这两者之间的唯一不同是id表示的结果将是当比较对象实例时用到的标识属性。这帮助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射)。
属性 |
描述 |
property |
映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans的属性,那么就会使用。否则MyBatis将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一些东西:“username”,或者映射到一些复杂的东西:“address.street.number”。 |
column |
从数据库中得到的列名,或者是列名的重命名标签。这也是通常和会传递给resultSet.getString(columnName)方法参数中相同的字符串。 |
javaType |
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一个JavaBean,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType来保证所需的行为。 |
jdbcType |
在这个表格之后的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。如果你直接使用JDBC编程,你需要指定这个类型-但仅仅对可能为空的值。 |
typeHandler |
我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。 |
构造方法
<constructor> <idArg column="id" javaType="int"/> <arg column=”username” javaType=”String”/> </constructor>
对于大多数数据传输对象(Data Transfer Object,DTO)类型,属性可以起作用,而且像绝大多数的领域模型,指令也许是你想使用一成不变的类的地方。通常包含引用或查询数据的表很少或基本不变的话对一成不变的类来说是合适的。构造方法注入允许你在初始化时为类设置属性的值,而不用暴露出公有方法。MyBatis也支持私有属性和私有JavaBeans属性来达到这个目的,但是一些人更青睐构造方法注入。Constructor(构造方法)元素支持这个。
public class User { //… public User(int id, String username) { //… } //… }为了向这个构造方法中注入结果,MyBatis需要通过它的参数的类型来标识构造方法。Java没有自查(或反射)参数名的方法。所以当创建一个构造方法元素时,保证参数是按顺序排列的,而且数据类型也是确定的。
<constructor> <idArg column="id" javaType="int"/> <arg column=”username” javaType=”String”/> </constructor>剩余的属性和规则和固定的id和result元素是相同的。
<association property="author" column="blog_author_id" javaType=" Author"> <id property="id" column="author_id"/> <result property="username" column="author_username"/> </association>
属性 |
描述 |
property |
映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同的JavaBeans的属性,那么就会使用。否则MyBatis将会寻找给定名称的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你可以这样映射一些东西:“username”,或者映射到一些复杂的东西:“address.street.number”。 |
column |
来自数据库的列名,或重命名的列标签。这和通常传递给resultSet.getString(columnName)方法的字符串是相同的。 注意:要处理复合主键,你可以指定多个列名通过column=”{prop1=col1,prop2=col2}”这种语法来传递给嵌套查询语句。这会引起prop1和prop2以参数对象形式来设置给目标嵌套查询语句。 |
javaType |
一个Java类的完全限定名,或一个类型别名(参加上面内建类型别名的列表)。如果你映射到一个JavaBean,MyBatis通常可以断定类型。然而,如果你映射到的是HashMap,那么你应该明确地指定javaType来保证所需的行为。 |
jdbcType |
在这个表格之前的所支持的JDBC类型列表中的类型。JDBC类型是仅仅需要对插入,更新和删除操作可能为空的列进行处理。这是JDBC的需要,而不是MyBatis的。如果你直接使用JDBC编程,你需要指定这个类型-但仅仅对可能为空的值。 |
typeHandler |
我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理器的实现,或者是类型别名。 |
关联的嵌套查询
select |
另外一个映射语句的ID,可以加载这个属性映射需要的复杂类型。获取的在列属性中指定的列的值将被传递给目标select语句作为参数。表格后面有一个详细的示例。 注意:要处理复合主键,你可以指定多个列名通过column=”{prop1=col1,prop2=col2}”这种语法来传递给嵌套查询语句。这会引起prop1和prop2以参数对象形式来设置给目标嵌套查询语句。 |
<resultMap id=”blogResult” type=”Blog”> <association property="author" column="blog_author_id" javaType="Author" select=”selectAuthor”/> </resultMap> <select id=”selectBlog” parameterType=”int” resultMap=”blogResult”> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id=”selectAuthor” parameterType=”int” resultType="Author"> SELECT * FROM AUTHOR WHERE ID = #{id} </select>我们有两个查询语句:一个来加载博客,另外一个来加载作者,而且博客的结果映射描述了“selectAuthor”语句应该被用来加载它的author属性。
关联的嵌套结果
resultMap |
这是结果映射的ID,可以映射关联的嵌套结果到一个合适的对象图中。这是一种替代方法来调用另外一个查询语句。这允许你联合多个表来合成到一个单独的结果集。这样的结果集可能包含重复,数据的重复组需要被分解,合理映射到一个嵌套的对象图。为了使它变得容易,MyBatis让你“链接”结果映射,来处理嵌套结果。例子会很容易来仿照,这个表格后面也有一个示例。 |
<select id="selectBlog" parameterType="int" resultMap="blogResult"> 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 From Blog B left outer join Author A on B.author_id = A.id where B.id = #{id} </select>注意这个联合查询,以及采取保护来确保所有结果被唯一而且清晰的名字来重命名。这使得映射非常简单。现在我们可以映射这个结果:
<resultMap id="blogResult" type="Blog"> <id property=”blog_id” column="id" /> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" javaType="Author" resultMap=”authorResult”/> </resultMap> <resultMap id="authorResult" type="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"/> </resultMap>非常重要:在嵌套结果映射中id元素扮演了非常重要的角色。应该通常指定一个或多个属性,它们可以用来唯一标识结果。实际上就是如果你不使用它(id元素),但是会产生一个严重的性能问题,不过MyBatis仍然可以正常工作。选择的属性越少越好,它们可以唯一地标识结果。主键就是一个显而易见的选择(即便是联合主键)。
<resultMap id="blogResult" type="Blog"> <id property=”blog_id” column="id" /> <result property="title" column="blog_title"/> <association property="author" column="blog_author_id" 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"/> </association> </resultMap>
集合
<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>集合元素的作用几乎和关联是相同的。实际上,它们也很相似。
<resultMap id=”blogResult” type=”Blog”> <collection property="posts" javaType=”ArrayList” column="blog_id" ofType="Post" select=”selectPostsForBlog”/> </resultMap> <select id=”selectBlog” parameterType=”int” resultMap=”blogResult”> SELECT * FROM BLOG WHERE ID = #{id} </select> <select id=”selectPostsForBlog” parameterType=”int” resultType="Author"> SELECT * FROM POST WHERE BLOG_ID = #{id} </select>首先,你应该注意我们使用的是集合元素。然后要注意那个新的“ofType”属性。这个属性用来区分JavaBean(或字段)属性类型和集合包含的类型来说是很重要的。所以你可以读出下面这个映射:
<collection property="posts" javaType=”ArrayList” column="blog_id" ofType="Post" select=”selectPostsForBlog”/>读作:“在Post类型的ArrayList中的posts的集合。”
<select id="selectBlog" parameterType="int" 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>现在用文章映射集合映射博客,可以简单写为:
<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元素的重要性。
<resultMap id="blogResult" type="Blog"> <id property=”id” column="blog_id" /> <result property="title" column="blog_title"/> <collection property="posts" ofType="Post" resultMap=”blogPostResult”/> </resultMap> <resultMap id="blogPostResult" type="Post"> <id property="id" column="post_id"/> <result property="subject" column="post_subject"/> <result property="body" column="post_body"/> </resultMap>
<discriminator javaType="int" column="draft"> <case value="1" resultType="DraftPost"/> </discriminator>有时一个单独的数据库查询也许返回很多不同(但是希望有些关联)数据类型的结果集。鉴别器元素就是被设计来处理这个情况的,还有包括类的继承层次结构。鉴别器非常容易理解,因为它的表现很像Java语言中的switch语句。
<resultMap id="vehicleResult" type="Vehicle"> <id property=”id” column="id" /> <result property="vin" column="vin"/> <result property="year" column="year"/> <result property="make" column="make"/> <result property="model" column="model"/> <result property="color" column="color"/> <discriminator javaType="int" column="vehicle_type"> <case value="1" resultMap="carResult"/> <case value="2" resultMap="truckResult"/> <case value="3" resultMap="vanResult"/> <case value="4" resultMap="suvResult"/> </discriminator> </resultMap> <resultMap id="carResult" type="Car"> <result property=”doorCount” column="door_count" /> </resultMap>上面示例中,MyBatis会从结果集中得到每条记录,然后比较它的vehicle类型的值。如果它匹配任何一个鉴别器的实例,那么就使用这个实例指定的结果映射。
<resultMap id="vehicleResult" type="Vehicle"> <id property=”id” column="id" /> <result property="vin" column="vin"/> <result property="year" column="year"/> <result property="make" column="make"/> <result property="model" column="model"/> <result property="color" column="color"/> <discriminator javaType="int" column="vehicle_type"> <case value="1" resultType="carResult"> <result property=”doorCount” column="door_count" /> </case> <case value="2" resultType="truckResult"> <result property=”boxSize” column="box_size" /> <result property=”extendedCab” column="extended_cab" /> </case> <case value="3" resultType="vanResult"> <result property=”powerSlidingDoor” column="power_sliding_door" /> </case> <case value="4" resultType="suvResult"> <result property=”allWheelDrive” column="all_wheel_drive" /> </case> </discriminator> </resultMap>