• MyBatis之Mapper XML 文件详解(三)-Result Maps


    resultMap 元素是 MyBatis 中最重要最强大的元素。它就是让你远离 90%的需要从结果 集中取出数据的 JDBC 代码的那个东西, 而且在一些情形下允许你做一些 JDBC 不支持的事 情。 事实上, 编写相似于对复杂语句联合映射这些等同的代码, 也许可以跨过上千行的代码。 

    ResultMap 的设计就是简单语句不需要明确的结果映射,而很多复杂语句确实需要描述它们 的关系。 


    你已经看到简单映射语句的示例了,但没有明确的 resultMap。比如:

    <select id="selectUsers" resultType="map">
     select id, username, hashedPassword
     from some_table
     where id = #{id}
    </select>

    这样一个语句简单作用于所有列被自动映射到 HashMap 的键上,这由 resultType 属性 指定。这在很多情况下是有用的,但是 HashMap 不能很好描述一个领域模型。那样你的应 用程序将会使用 JavaBeans 或 POJOs(Plain Old Java Objects,普通 Java 对象)来作为领域 模型。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;
     }
    }

    基于 JavaBean 的规范,上面这个类有 3 个属性:id,username 和 hashedPassword。这些 在 select 语句中会精确匹配到列名。 


    这样的一个 JavaBean 可以被映射到结果集,就像映射到 HashMap 一样简单。

    <select id="selectUsers" resultType="com.someapp.model.User">
     select id, username, hashedPassword
     from some_table
     where id = #{id}
    </select>

    要记住类型别名是你的伙伴。使用它们你可以不用输入类的全路径。比如:

    <!-- In mybatis-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>

    如果世界总是这么简单就好了。 


    高级结果映射
    MyBatis 创建的一个想法:数据库不用永远是你想要的或需要它们是什么样的。而我们 最喜欢的数据库最好是第三范式或 BCNF 模式,但它们有时不是。如果可能有一个单独的 数据库映射,所有应用程序都可以使用它,这是非常好的,但有时也不是。结果映射就是 MyBatis 提供处理这个问题的答案。 


    比如,我们如何映射下面这个语句?

    <!-- 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>

    你可能想把它映射到一个智能的对象模型,包含一个作者写的博客,有很多的博文,每 篇博文有零条或多条的评论和标签。 下面是一个完整的复杂结果映射例子 (假设作者, 博客, 博文, 评论和标签都是类型的别名) 我们来看看, 。 但是不用紧张, 我们会一步一步来说明。 当天最初它看起来令人生畏,但实际上非常简单。

    <!-- 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 元素有很多子元素和一个值得讨论的结构。 下面是 resultMap 元素的概念视图 
    resultMap
    constructor - 类在实例化时,用来注入结果到构造方法中 
        idArg - ID 参数;标记结果作为 ID 可以帮助提高整体效能
        arg- 注入到构造方法的一个普通结果
    id – 一个 ID 结果;标记结果作为 ID 可以帮助提高整体效能
    result – 注入到字段或 JavaBean 属性的普通结果
    association – 一个复杂的类型关联;许多结果将包成这种类型 
        嵌入结果映射 – 结果映射自身的关联,或者参考一个 
    collection – 复杂类型的集 
        嵌入结果映射 – 结果映射自身的集,或者参考一个
    discriminator – 使用结果值来决定使用哪个结果映射 
        case – 基于某些值的结果映射 
            嵌入结果映射 – 这种情形结果也映射它本身,因此可以包含很多相 同的元素,或者它可以参照一个外部的结果映射。 

    ResultMap Attributes

    id:当前命名空间中的一个唯一标识,用于标识一个result map.
    type:类的全限定名, 或者一个类型别名 (内置的别名可以参考上面的表格). 
    autoMapping:如果设置这个属性,MyBatis将会为这个ResultMap开启或者关闭自动映射。这个属性会覆盖全局的属性autoMappingBehavior。默认值为:unset。 


    最佳实践 通常逐步建立结果映射。单元测试的真正帮助在这里。如果你尝试创建 一次创建一个向上面示例那样的巨大的结果映射, 那么可能会有错误而且很难去控制它 来工作。开始简单一些,一步一步的发展。而且要进行单元测试!使用该框架的缺点是 它们有时是黑盒(是否可见源代码) 。你确定你实现想要的行为的最好选择是编写单元 测试。它也可以你帮助得到提交时的错误。 


    下面一部分将详细说明每个元素。 
    id & result

    <id property="id" column="post_id"/>
    <result property="subject" column="post_subject"/>

    这些是结果映射最基本内容。id 和 result 都映射一个单独列的值到简单数据类型(字符 串,整型,双精度浮点数,日期等)的单独属性或字段。 


    这两者之间的唯一不同是 id 表示的结果将是当比较对象实例时用到的标识属性。这帮 助来改进整体表现,特别是缓存和嵌入结果映射(也就是联合映射) 。 


    每个都有一些属性: 
    Id and Result Attributes

    property:映射到列结果的字段或属性。如果匹配的是存在的,和给定名称相同 的 JavaBeans 的属性,那么就会使用。否则 MyBatis 将会寻找给定名称 property 的字段。这两种情形你可以使用通常点式的复杂属性导航。比如,你 可以这样映射一些东西: “username” ,或者映射到一些复杂的东西: “address.street.number” 。 
    column:从数据库中得到的列名,或者是列名的重命名标签。这也是通常和会 传递给 resultSet.getString(columnName)方法参数中相同的字符串。 
    javaType:一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名 的列表) 。如果你映射到一个 JavaBean,MyBatis 通常可以断定类型。 然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证所需的行为。 
    jdbcType:在这个表格之后的所支持的 JDBC 类型列表中的类型。JDBC 类型是仅 仅需要对插入,更新和删除操作可能为空的列进行处理。这是 JDBC jdbcType 的需要,而不是 MyBatis 的。如果你直接使用 JDBC 编程,你需要指定 这个类型-但仅仅对可能为空的值。 
    typeHandler:我们在前面讨论过默认的类型处理器。使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是类的完全限定名或者是一个类型处理 器的实现,或者是类型别名。

    关注微信公众号:IT哈哈(it_haha),学习更多知识。

  • 相关阅读:
    条款十四 在资源管理类中小心copying行为
    条款八 别让异常逃离析构函数
    条款五 了解C++默默的编写并调用的哪些函数
    volatile——C++关键字(转)
    C++ auto_ptr(转)
    条款十三 以对象管理资源
    优秀文章收集(更新中..)
    条款十一 在operator = 中处理"自我赋值"
    TCP协议疑难杂症全景解析(转)
    大四的迷茫
  • 原文地址:https://www.cnblogs.com/baiyu28/p/9267295.html
Copyright © 2020-2023  润新知