MyBatis - explain ResultMap result mapping

One heart students will explain the most powerful element of MyBatis - ResultMap in this chapter. Let's enjoy its charming place together.

1. Introduction to resultmap

resultMap element is not only the most important and powerful element in MyBatis, but also one of the most complex elements in MyBatis. It is a database mapping schema. Describes how to load objects from the result set. It is mainly used to define mapping rules, cascade updates, and custom type converters.

Function: solve the mapping problem from database to object.

Here, let's first understand the constituent elements of ResultMap:

Constituent elements of ResultMap:

  • constructor  - When instantiating a class, inject the result into the constructor
            idArg  - ID   Parameters;   Mark the result set as ID to facilitate global invocation
              arg  - Inject the result set of the constructor
  • id  – Result set ID, which marks the result set as ID to facilitate global call
  • result  – Common results injected into fields or JavaBean properties
  • association  – An association; A one-to-one relationship that wraps the results into this type
    Nested result mapping – associations can refer to themselves or from elsewhere
  • collection  – A collection of complex types, one to many relationships
    Nested result mapping – collections can refer to themselves or from elsewhere
  • discriminator  – Use the result value to decide which to use   resultMap
  • case  – Result mapping based on some values
    Nested result mapping –   case   It is also a result mapping, so it has the same structure and elements; Or reference other result mappings

Next, let's focus on the students' explanation.

2.id & result

Entity class:

public class Blog {
 private int id;
 private String name;
 private String password;//The password here is inconsistent with the pwd of the database
 //set,get, no parameter, with parameter
}

Interface:

public Blog selectBlogById(int id);

Mapping file:

<resultMap id="blogResult" type="Blog">
 <id column="id" property="id"/><!--Primary key mapping-->
 <result column="pwd" property="password"/><!--Mapping of database table fields to entity class attributes-->
 <result column="name" property="name"/>
</resultMap>
<select id="selectBlogById" parameterType="int" resultMap="blogResult">
 select * from blog where id=#{id}
</select>

First, let's talk about each attribute in easy to understand words.
Attributes of id and result:

id: generally used as primary key mapping to facilitate global calling.
result: mapping of database table fields to entity class attributes.
column: database field name
Property: entity property name
javaType: refers to the type of the attribute of the Java class. It can be a fully qualified name or a type alias (for example, the type alias of int is _int, and the type alias of integer is int). If it is mapped to a JavaBean, MyBatis can automatically infer the type, that is, we don't need to write it.

The detailed explanation of each attribute is as follows:

Property list of ResultMap
attributedescribe
idPrimary key, a unique identifier in the current namespace, used to identify a result mapping.
typeThe fully qualified name of the class, or a type alias
autoMappingIf this property is set, MyBatis will turn on or off automatic mapping for this result mapping. This property overrides the global property autoMappingBehavior. Default: unset.
The details of id and result attributes are as follows:
Properties of Id and Result
attributedescribe
propertyAttribute names that need to be mapped to JavaBean s.
columnThe column name in the database, or the alias of the column.
javaTypeThe fully qualified name of a Java class, or a type alias. If you map to a JavaBean, MyBatis can usually automatically infer types. However, if you are mapping to a HashMap, you should explicitly specify a javaType to ensure that the behavior is consistent with expectations.
jdbcTypeList of types supported by the data table. This attribute is only useful for columns that allow nulls during insert,update or delete. JDBC requires this, but MyBatis does not. If you are directly encoding for JDBC and have columns that allow null, you need to specify this item.
typeHandlerThis property can override the default processor type. This property value is the fully qualified name of a type processor implementation class, or a type alias.

2.CONSTRUCTOR construction method

Introduction: constructor injection allows you to set the value of the property for the class during initialization without exposing the public method.

Construction method:

public Blog(@Param("id") int id, @Param("name") String name, @Param("password") String password) {
 this.id = id;
 this.name = name;
 this.password = password;
}
Mapping file:
<resultMap id="constructResult" type="Blog">
 <constructor>
 <idArg column="id" javaType="_int" name="id"/>
 <arg column="name" javaType="String" name="name"/>
 <arg column="pwd" javaType="String" name="password"/>
 </constructor>
</resultMap>
<select id="selectBlogById" parameterType="int" resultMap="constructResult">
 select * from blog where id=#{id}
</select>


Explanation:

idArg: it is generally used as a primary key element to facilitate global calling. javaType: refers to the type of the attribute of the Java class, which can be a fully qualified name or a type alias (for example, the type alias of int is _int, and the type alias of integer is int). Name: refers to the parameter name of the constructor. You need to specify the name of the corresponding attribute with @ Param("specify name") for the constructor, otherwise MyBatis doesn't know.

3. association

Introduction: the one-to-one relationship packages the results into this type, for example:

A blog has only one author, but an author can have multiple blogs, so the author should be associated with the blog. For a blog, he only needs to identify one author, that is, 1 to 1.

Blog entity class:

public class Blog {
 private int id;
 private String name;
 private String pwd;
 private Author author;
 //set,get, no parameter, with parameter
}

Author entity class:

public class Author {
 private int author_id;
 private String author_name;
 private String author_pwd;
 //set,get, no parameter, with parameter
}

Note: there are two entity classes now, which means that in order to standardize, you need to create a directory with the same entity class in the resource directory, move the two mapping files AuthorMapper.xml and BlogMapper.xml to this directory, and remember to re match the path of the configuration file for standardization. Of course, you can do otherwise, But when the project is large, it will be very difficult to maintain.

Configuration file configuration path:

<mappers>
 <mapper resource="com/yixin/dao/BlogMapper.xml"/>
 <mapper resource="com/yixin/dao/AuthorMapper.xml"/>
</mappers>

This is a screenshot of my directory:

 

MyBatis loads associations in two different ways:

  • Nested Select query: load the desired complex type by executing another SQL mapping statement.
  • Nested result mapping: use nested result mapping to handle duplicate subsets of connected results.

3.1 associated nested Select query

Properties:

Select: the ID of the mapping statement used to load the complex type attribute. It will retrieve data from the column specified by the column attribute and pass it to the target select statement as a parameter.

AuthorMapper interface:

public interface AuthorMapper {
 public Author getAuthor(int author_id);
}

BlogMapper interface:

public interface BlogMapper {
 public Blog selectBlogById(int id);
}

Mapping file:

AuthorMapper.xml

<mapper namespace="com.yixin.dao.AuthorMapper">

 <select id="getAuthor" resultType="Author">
 select * from author where author_id=#{id}<!-- There is only one attribute, and the ID can take any value -- >
 </select>
</mapper>
BlogMapper.xml
<mapper namespace="com.yixin.dao.BlogMapper">
<resultMap id="blogResultSelect" type="Blog">
 <id column="id" property="id"/>
 <result column="pwd" property="pwd"/>
 <result column="name" property="name"/>
 <!---Since the above three attributes are the same as the database fields, they can not be written. This is just for your understanding-->
 <association property="author" column="author_id" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthor"/>
 </resultMap>
 <select id="selectBlogById" parameterType="int" resultMap="blogResultSelect">
 select * from blog where id=#{id}
 </select>
</mapper>


Explanation:
Property: the property name of the entity
column: the field name of the database
javaType: indicates that the type passed to the entity object is Author
select: get the column to the Author_ The id value is passed in, and getAuthor gets the Author object according to the passed in id value and returns it.



Note: if you want to determine the Author's object through two or more parameters, the value of column can be divided with ",".
AuthorMapper.xml

<select id="getAuthorByIdAndName" resultType="Author">
 select * from author where author_id=#{id} and author_name=#{name}
</select>

BlogMapper.xml

<select id="selectBlogById" parameterType="int" resultMap="blogResultSelectByIdName">
 select * from blog where id=#{id}
</select>
<resultMap id="blogResultSelectByIdName" type="Blog">
 <association property="author" column="{id=id,name=name}" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthorByIdAndName"/>
</resultMap>

Explanation:

Use the id and name defined in the column, and then use select to pass the id and name into getAuthorByIdAndName. Enter and return Author

3.2 associated nested result mapping

Properties:

resultMap: the ID of the result map, which can map the associated nested result set to an appropriate object tree.

There are two types of nested result mapping:

1. The result mapping is nested as child elements

2. External result mapping element to map Association

3.2.1 result mapping nested as child elements

Interface method:
public Blog selectBlog();
Mapping file:
<select id="selectBlog" resultMap="blogResultMap">
 select a.*,b.* from blog b,author a
</select>
 <resultMap id="blogResult" type="Blog">
 <id column="id" property="id"/>
 <result column="name" property="name"/>
 <result column="pwd" property="pwd"/>
 <association property="author" javaType="Author" >
 <id column="author_id" property="author_id"/>
 <result column="author_name" property="author_name"/>
 <result column="author_pwd" property="author_pwd"/>
 </association>
 </resultMap>

Explanation:

Query all the attributes of the two tables, and then use these attributes to allocate them in the Blog. association uses these attributes to generate an Author object.


be careful:
  id element plays a very important role in nested result mapping. You should always specify one or more properties that uniquely identify the result. Although MyBatis works even if this attribute is not specified, it will cause serious performance problems.


3.2.2. External result mapping element to map Association


The characteristic of this method is that the sub result mapping is reusable.
Mapping file:

<resultMap id="blogResultMap" type="Blog">
 <id column="id" property="id"/>
 <result column="name" property="name"/>
 <result column="pwd" property="pwd"/>
 <association property="author" column="author_id" javaType="Author" resultMap="getAuthor"/>
</resultMap>
<resultMap id="getAuthor" type="Author">
 <id column="author_id" property="author_id"/>
 <result column="author_name" property="author_name"/>
 <result column="author_pwd" property="author_pwd"/>
</resultMap>


Explanation:

After all elements are queried, another resultMap, getauthor, is nested with resultMap. Getauthor can also get all attribute fields and generate an Author object to return.
 

4.collection one-to-one multi-level connection

Explanation: an Author can have multiple blogs. In order to obtain all blogs of the Author, we can define the entity class Author as follows

public class Author {
 private int author_id;
 private String author_name;
 private String author_pwd;
 private List<Blog> blogs;
//get,set, parameterized construction, nonparametric construction
}

There are two ways to implement such mapping files:

1. Nested Select query of collection

2. Nested result mapping of sets

4.1 nested Select query of collection

Interface:

public Author getAuthor(int author_id);

Mapping file:

AuthorMapper.xml

<select id="getAuthor" resultMap="authorResult2">
 select a.*,b.* from blog b,author a where b.author_id=#{id}
</select>
<resultMap id="authorResult2" type="Author">
 <id column="author_id" property="author_id"/>
 <result column="author_name" property="author_name"/>
 <result column="author_pwd" property="author_pwd"/>
 <collection property="blogs" javaType="ArrayList" column="id" ofType="Blog"
 select="com.yixin.dao.BlogMapper.selectBlogById"/>
</resultMap>

BlogMapper.xml

<select id="selectBlogById" parameterType="int" resultMap="blogResultSelectByIdName">
 select * from blog where id=#{id}
</select>
<resultMap id="blogResultSelectByIdName" type="Blog">
 <association property="author" column="{id=id,name=name}" javaType="Author" select="com.yixin.dao.AuthorMapper.getAuthorByIdAndName"/>
</resultMap>

Explanation:

column gets the field id, passes it to select, and then returns a Blog to form a collection of blogs.

Collection:

  • Both JavaType and ofType are used to specify the object type
          JavaType is used to specify the type of property in pojo.
          ofType specifies the type mapped to pojo in the list collection property.

4.2 nested result mapping of sets

Mapping file:

<select id="getAuthor" resultMap="authorResult2">
    select a.*,b.* from blog b,author a where b.author_id=#{id}
</select>
<resultMap id="authorResult" type="Author">
    <id column="author_id" property="author_id"/>
    <result column="author_name" property="author_name"/>
    <result column="author_pwd" property="author_pwd"/>
    <collection property="blogs" ofType="Blog">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="pwd"/>
    </collection>
</resultMap>
 

Explanation:

ofType: Specifies the type mapped to pojo in the list collection attribute.

Property: the property name of the collection.

5. Discriminator

Introduction:

Sometimes, a database query may return multiple different result sets. The discriminator element is designed to deal with this situation. In addition, it can also deal with other situations, such as the inheritance hierarchy of classes. The concept of a discriminator is well understood -- it's much like a switch statement in the Java language.

Understanding: an author's Blog can have many types, including technology type, entertainment type, work type, etc. these types of blogs inherit the Blog class. When we want to find a certain type of Blog and load it, we need to use the discriminator.

class TechnologyBlog extends Blog{
 private String study;
}
class PlayBlog extends Blog{
 private String game;
}

Use the best_blog attribute to determine which blog to load.

The attributes of the Author table are as follows:

int id,

String name,

String pwd,

int type_blog,

study,

game.

Mapping file:

<resultMap id="BlogResult" type="Vehicle">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="pwd" column="pwd"/>

<discriminator javaType="int" column="type_blog">
<case value="1" resultMap="technologyResult"/>
<case value="2" resultMap="playResult"/>
</discriminator>
</resultMap>
<resultMap id="technologyResult" type="TechnologyBlog" extends="BlogResult">
<result property="study" column="study" />
</resultMap>
<resultMap id="playResult" type="PlayBlog" extends="BlogResult">
<result property="game" column="game" />
</resultMap>

Explanation:

MyBatis will get each record from the result set, and then compare its best_blog value. If it matches the case of any discriminator, it will use the result map specified by this case. Just like the inheritance relationship, resultMap can also inherit and add its own attributes based on the parent class.

Note: this process is mutually exclusive, that is, the remaining result mappings will be ignored.

If the matched technologyResult is technologyResult, only the TechnologyBlog class will be loaded, and the returned result will also return the object TechnologyBlog.

After reading the above code, if you think it is too complex and prefer a concise mapping style, you can also change to the following writing method:

<resultMap id="BlogResult" type="Vehicle">
<id property="id" column="id" />
<result property="name" column="name"/>
<result property="pwd" column="pwd"/>

<discriminator javaType="int" column="type_blog">
<case value="1" resultType="TechnologyBlog">
<result property="study" column="study" />
</case>
<case value="2" resultType="PlayBlog"/>
<result property="game" column="game" />
</case>
</discriminator>
</resultMap>

summary

1. association Association

2. Collection collection

3. association is used for one-to-one and many to one, while collection is used for one to many relationships

4. Both JavaType and ofType are used to specify the object type

  • JavaType is used to specify the type of property in pojo

  • ofType specifies the type mapped to pojo in the list collection property.

epilogue

The above is the explanation of ResultMap, the most powerful element of MyBatis. Through document sorting and computer practice, it really costs me a lot of energy to tell the truth, because there are a lot of knowledge points, but at the same time, it also makes me realize the strength of ResultMap. Tomorrow, Xinyi will be resurrected with blood, that is, the next blog will continue to serve you Explain the automatic mapping in the mapping file.

 

Tags: Java Mybatis xml Back-end IDE

Posted on Tue, 30 Nov 2021 12:00:46 -0500 by sunnyk