I was a little addicted to mapping Value Objects in MyBatis, so I organized them.
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>
select
, add @Param
annotation@Param
, addparameterType = "map"
to the option of select
Without the above, the value of the Value Object could not be used in the select
, such aswhere id = # {userId.value}
.
constructor
to map a value to the Value Object's constructorname
of ʻarg`The following part.
<association property="userId" javaType="com.example.demo.domain.model.UserId">
<constructor>
<arg name="value" column="id"/>
</constructor>
</association>
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.
Recommended Posts