[JAVA] Points when mapping Value Object in MyBatis

Preface

I was a little addicted to mapping Value Objects in MyBatis, so I organized them.

What you want to achieve

environment

Implementation

Suppose you have a Value Object class called ʻUserName` like this:

package com.example.demo.domain.model;

public class UserName {
    private final String value;

    public UserName(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}

The ʻUser class holds the ʻUserName. It also holds the classes ʻUserName and RegisterDate`.

package com.example.demo.domain.model;

import lombok.Data;

@Data
public class User {
    private UserId userId;
    private UserName userName;
    private RegisterDate registerDate;
}

Write the DB definition in schema.sql.

CREATE TABLE users (
  id int NOT NULL
  , user_name VARCHAR(50)  
  , register_date DATE
);

Data.sql for inserting data for testing.

INSERT INTO users VALUES (1, 'Nocchi', '2020-02-01');
INSERT INTO users VALUES (2, 'Kashiyuka', '2020-02-02');
INSERT INTO users VALUES (3, 'A-Chan', '2020-02-03');

Define a method findById in ʻUserRepository to get ʻUser from the ID.

package com.example.demo.domain.repository;

import com.example.demo.domain.model.User;
import com.example.demo.domain.model.UserId;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Mapper
@Repository
public interface UserRepository {
    User findById(@Param("userId") UserId userId);
}

Mapper has the following contents.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.domain.repository.UserRepository">
  <select id="findById" resultMap="UserMap" parameterType="map">
    select id, user_name, register_date from users where id = #{userId.value}
  </select>

  <resultMap id="UserMap" type="com.example.demo.domain.model.User">
      <association property="userId" javaType="com.example.demo.domain.model.UserId">
        <constructor>
          <arg name="value" column="id"/>
        </constructor>
      </association>
      <association property="userName" javaType="com.example.demo.domain.model.UserName">
        <constructor>
          <arg name="value" column="user_name"/>
        </constructor>
      </association>
      <association property="registerDate" javaType="com.example.demo.domain.model.RegisterDate">
        <constructor>
          <arg name="value" column="register_date"/>
        </constructor>
      </association>
  </resultMap>

</mapper>

point

Without the above, the value of the Value Object could not be used in the select, such aswhere id = # {userId.value}.

The following part.

<association property="userId" javaType="com.example.demo.domain.model.UserId">
        <constructor>
          <arg name="value" column="id"/>
        </constructor>
</association>

result

The result of writing the test code and breaking it is as follows. An instance of the Value Object has also been created and the values have been mapped.

スクリーンショット 2020-02-06 5.41.18.png

code

Published on GitHub.

Recommended Posts

Points when mapping Value Object in MyBatis
Mapping to a class with a value object in How to MyBatis
Value object in 3 minutes
Initial value when there is no form object property in Spring request
Points stuck when running vite + Nginx in Docker environment
JAVA object mapping library
How to pass an object to Mapper in MyBatis without arguments
[MyBatis] Use Cursor when mapping a large amount of data