2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

MyBatis にて値オブジェクト(Value Object)をマッピングさせる際のポイント

Posted at

前置き

MyBatis にて値オブジェクト(Value Object)をマッピングさせる際に少しハマったので整理しました。

実現させたいこと

  • SELECT の結果をオブジェクト内の Value Object にマッピングさせたい
  • SELECT のパラメーターを Value Object にしたい

環境

  • Spirng Boot
  • MyBatis
  • h2 DataBase

実装

以下のようなUserNameという Value Object クラスがあったとします。

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;
    }
}

UserクラスがUserNameを保持します。
他にUserNameRegisterDateというクラスも保持しています。

package com.example.demo.domain.model;

import lombok.Data;

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

schema.sqlにDB定義を書きます。

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

テスト用のデータ挿入用のdata.sqlです。

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');

UserRepositoryにIDからUserを取得するためのメソッドfindByIdを定義します。

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 は以下のような内容になります。

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

ポイント

  • Value Object を selectの Parameter に使用したい場合@Paramアノテーションをつける
  • @Paramを使用する場合、selectのオプションにparameterType="map"を付与する

上記を行わないと、where id = #{userId.value} のように Value Object の値をselect内で使用できませんでした。

  • SELECT結果のオブジェクト内の Value Object インスタンスを生成するには、associationを使用する
  • Value Object の コンストラクタに値をマップさせるためにconstructorを使用する
  • argのオプションnameで、引数名を指定する

以下の部分です。

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

結果

テストコードを書いてブレークさせた結果は以下のように。
Value Object のインスタンスも生成されて、値もマップされています。

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

コード

GitHub に公開しました。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?