ResultMap of MyBatis association mapping

1. Introduction to ResultMap

MyBtis association mapping has to mention the ResultMap element
The resultMap element is the most important and powerful element in MyBatis.
One of the ideas when MyBatis was created is that the database cannot always be what you think or need. We'd like every database to be in good third normal form, or BCNF, but unfortunately not all of them are. It would be great if there was a single database mapping schema that would fit all applications perfectly, but unfortunately there isn't one. And ResultMap is MyBatis' answer to this question.
By default, when the MyBatis program is running, it will automatically match the queried data with the properties of the object that needs to be returned (the column names in the data package are exactly the same as the object property names to match the successful assignment). However, in the actual development process, the columns in the data table may not be completely consistent with the properties of the object to be returned. In this case, MyBatis will not automatically assign values. In this case, the resultMap element needs to be used for structural mapping. In another case, the query is to map complex data (query data in several tables) to a result set. In this case, use resultMap for custom result mapping. The field names can be inconsistent, and you can also specify what to display Columns are more flexible and widely used (recommended).

2. ResultMap simple mapping instance

2.1 Database and entity class preparation

create table tbl_user (
    user_id int primary key auto_increment,
    user_name varchar(20) not null,
    user_age int not null
);
insert into tbl_user (user_id,user_name,user_age) values(null,'张三',20),(null,'李四',18);
package com.biem.pojo;

import lombok.*;

/**
 * ClassName: User
 * Package: com.biem.pojo
 * Description:
 *
 * @Create 2023/4/19 9:27
 * @Version 1.0
 */
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    
    private Integer id;
    private String name;
    private Integer age;
}

2.2 Queries in UserMapper.xml

    <select id="findUserById" resultType="user">
        select  user_id, user_name, user_age  from tbl_user where user_id=#{id}
    </select>

The result is as follows:

DEBUG 04-19 09:53:36,303 ==>  Preparing: select user_id, user_name, user_age from tbl_user where user_id=?  (BaseJdbcLogger.java:159) 
DEBUG 04-19 09:53:36,383 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG 04-19 09:53:36,460 <==      Total: 1 (BaseJdbcLogger.java:159) 
user = null

The reason is that the column name and the attribute name cannot match.
The column name is: user_id, user_name, user_age
The attribute name is: id, name, age

2.3 Solutions

2.3.1 Scenario 1: Set column aliases in the SELECT statement

    <select id="findUserById" resultType="user">
        select
            user_id as "id",
            user_name as "name",
            user_age as "age"
        from tbl_user
        where user_id=#{id}
    </select>

The result is as follows

DEBUG 04-19 09:54:51,717 ==>  Preparing: select user_id as "id", user_name as "name", user_age as "age" from tbl_user where user_id=?  (BaseJdbcLogger.java:159) 
DEBUG 04-19 09:54:51,882 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG 04-19 09:54:51,953 <==      Total: 1 (BaseJdbcLogger.java:159) 
user = User(id=1, name=张三, age=20)

2.3.2 Solution 2: Explicitly configure ResultMap

    <resultMap id="userResultMap" type="user">
        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>
        <result property="age" column="user_age"/>
    </resultMap>
    <select id="findUserById" resultMap="userResultMap">
        select
            user_id, user_name, user_age
        from tbl_user
        where user_id=#{id}
    </select>

The result is as follows:

DEBUG 04-19 14:29:17,036 ==>  Preparing: select user_id, user_name, user_age from tbl_user where user_id=?  (BaseJdbcLogger.java:159) 
DEBUG 04-19 14:29:17,121 ==> Parameters: 1(Integer) (BaseJdbcLogger.java:159) 
DEBUG 04-19 14:29:17,201 <==      Total: 1 (BaseJdbcLogger.java:159) 
user = User(id=1, name=张三, age=20)

3 resultMap attribute and child elements

3.1 Attribute list of ResultMap

Attributes describe
id A unique identifier in the current namespace that identifies a result map.
type The fully qualified name of the class, or a type alias
autoMapping If this property is set, MyBatis will enable or disable automatic mapping for this result mapping. This property overrides the global property autoMappingBehavior. Default: not set (unset).

3.2 resultMap child element

constructor - used to inject results into the constructor when instantiating the class

  • idArg - ID argument; flagging results as IDs can help improve overall performance
  • arg - an ordinary result that will be injected into the constructor

id – an ID result; marking results as IDs can help improve overall performance

result - the generic result injected into the field or JavaBean property

association – a complex type of association; many results will be wrapped into this type

  • Nested result maps – associations can be resultMap elements, or references to other result maps

collection – a collection of complex types

  • Nested result maps – collections can be resultMap elements, or references to other result maps

discriminator – use the result value to decide which resultMap to use

case – result mapping based on some values
  • Nested result maps – case is also a result map and thus has the same structure and elements; or references other result maps

3.3 Common sub-elements

3.3.1 id and result

        <id property="id" column="user_id"/>
        <result property="name" column="user_name"/>

These elements are the basis for the result map. Both the id and result elements map a column's value to a property or field of a simple data type (String, int, double, Date, etc.).

The only difference between the two is that the attribute corresponding to the id element will be marked as the identifier of the object, which is used when comparing object instances. This can improve overall performance, especially when caching and nested result maps (aka join maps).

Properties of Id and Result

Attributes describe
property The field or property that maps to the column result. If the JavaBean has a property with this name, it will be used first. Otherwise MyBatis will look for a field with the given name. In either case, you can use the usual dot-separated form for complex property navigation. For example, you can map something simple: "username", or something complex: "address.street.number".
column The column name in the database, or an alias for the column.
javaType The fully qualified name of a Java class, or a type alias (see the table above for built-in type aliases). If you map to a JavaBean, MyBatis can usually infer the type. However, if you are mapping to a HashMap, then you should explicitly specify the javaType to ensure the expected behavior.
jdbcType JDBC Types JDBC types need only be specified on columns where inserts, updates, and deletes are possible and that allow null values. This is a requirement of JDBC not MyBatis. If you're programming directly against JDBC, you need to specify this type for nullable columns.
typeHandler The default type handler. Using this attribute, you can override the default type handler. The property value is the fully qualified name of a type handler implementation class, or a type alias.

Supported JDBC types
For future possible usage scenarios, MyBatis supports the following JDBC types through the built-in jdbcType enumeration type.

BIT FLOAT CHAR TIMESTAMP OTHER UNDEFINED
TINYINT REAL VARCHAR BINARY BLOB NVARCHAR
SMALLINT DOUBLE LONGVARCHAR VARBINARY CLOB NCHAR
INTEGER NUMERIC DATE LONGVARBINARY BOOLEAN NCLOB
BIGINT DECIMAL TIME NULL CURSOR ARRAY

3.3.2 The constructor element

The constructor element is mainly used for tables containing references or data that rarely change or basically does not change, and is suitable for immutable classes . Constructor injection allows you to set property values ​​for a class at initialization time without exposing public methods. MyBatis also supports private properties and private JavaBean properties to complete the injection, but some people prefer to inject through the constructor.

3.3.3 Association

Association (association) elements deal with "has a" type of relationship. For example, in our example, a blog has a user. Association result mappings work in much the same way as other types of mappings. You need to specify the target property name and the javaType of the property (MyBatis can infer it by itself in many cases). You can also set the JDBC type if necessary, and you can also set the type handler if you want to override the process of getting the result value.

The difference with associations is that you need to tell MyBatis how to load the associations. MyBatis has two different ways to load associations:

Nested Select query: Load the desired complex type by executing another SQL mapping statement.
Nested result maps: Use nested result maps to handle repeated subsets of join results.

First, let's take a look at the attributes of this element. You'll notice that it differs only in the select and resultMap properties from normal result maps.

Attributes describe
property The field or property that maps to the column result. If a property with the given name exists on the matching JavaBean, it will be used. Otherwise MyBatis will look for a field with the given name. In either case, you can use the usual dot-separated form for complex property navigation. For example, you can map something simple: "username", or something complex: "address.street.number".
javaType The fully qualified name of a Java class, or a type alias (see the table above for built-in type aliases). If you map to a JavaBean, MyBatis can usually infer the type. However, if you are mapping to a HashMap, then you should explicitly specify the javaType to ensure the expected behavior.
jdbcType JDBC type, the supported JDBC types refer to "Supported JDBC types" before this table. JDBC types only need to be specified on columns where inserts, updates, and deletes are possible and that allow null values. This is a requirement of JDBC not MyBatis. If you are programming directly against JDBC, you need to specify this type for columns that may have null values.
typeHandler We discussed default type handlers earlier. Using this attribute, you can override the default type handler. The property value is the fully qualified name of a type handler implementation class, or a type alias.
3.3.3.1 Nested Select queries
Attributes describe
column The column name in the database, or an alias for the column. In general, this is the same parameter passed to the resultSet.getString(columnName) method. Note: When using a composite primary key, you can use the syntax column="{prop1=col1,prop2=col2}" to specify multiple column names passed to the nested Select query statement. This will cause prop1 and prop2 to be set as parameters of the corresponding nested Select statement as parameter objects.
select The ID of the mapping statement used to load complex type attributes, which retrieves data from the column specified by the column attribute, passed as a parameter to the target select statement. For details, please refer to the following example. Note: When using a composite primary key, you can use the syntax column="{prop1=col1,prop2=col2}" to specify multiple column names passed to the nested Select query statement. This will cause prop1 and prop2 to be set as parameters of the corresponding nested Select statement as parameter objects.
fetchType optional. Valid values ​​are lazy and eager. When the attribute is specified, the global configuration parameter lazyLoadingEnabled is ignored in the mapping, and the value of the attribute is used.
3.3.3.2 Nested Result Mapping
Attributes describe
resultMap The ID of the result map that maps this association's nested result sets into a suitable object tree. It can be used as an alternative to using an additional select statement. It can map the results of multi-table join operations into a single ResultSet. Such ResultSet has some data that is repeated. In order to correctly map result sets into nested object trees, MyBatis allows you to "concatenate" result maps in order to solve the problem of nested result sets. An example of using nested result maps follows the table.
columnPrefix When joining multiple tables, you may have to use column aliases to avoid duplicate column names in the ResultSet. Specifying columnPrefix column name prefixes allows you to map columns with these prefixes into an external result map. For details, please refer to the following examples.
notNullColumn By default, child objects are only created if at least one of the columns mapped to the property is not null. You can specify non-empty columns on this property to change the default behavior. After specifying, Mybatis will only create a child object when these columns are non-empty. Multiple columns can be specified separated by commas. Default: not set (unset).
autoMapping 如果设置这个属性,MyBatis 将会为本结果映射开启或者关闭自动映射。 这个属性会覆盖全局的属性 autoMappingBehavior。注意,本属性对外部的结果映射无效,所以不能搭配 select 或 resultMap 元素使用。默认值:未设置(unset)。

例子:MyBatis关联映射查询

Guess you like

Origin blog.csdn.net/yandao/article/details/130213112