Mapper XMLの内容紹介

## 0.前置き
Java開発で使用したMapper XMLについて紹介いたします。

## 1.目的
以前、紹介した以下の記事、
「MyBatisGeneratorを用いて、Model・Mapperの作成」
<https://qiita.com/yu-F/items/a612dc9b0ee4008c8b31>
で作成した、Mapper XMLの書き方の紹介（自動生成したものに手を加える場合）、
自動生成したDBのModelとの紐づけ方について、紹介します。

## 2.Mapper XMLで使用するタグについて

実装時に使用したCRUD系の主なタグのみ紹介

### （１）タグ「resultMap」
⇒今回は、自動生成時に作られるもの。（mybatis-generator-config.xmlの「table」の設定にもよる）
SELECTにおいての取得結果の列の格納先としてMappingで使用する。
内部では、タグ「result」でcolumn、jdbcType、propertyを宣言していくことで、取得列の情報を網羅する。propertyでは結果とするDTOの中の項目と突きあうようにする。

```java:MNentsukiShuKanriMapper.xml　（例）
  <resultMap id="BaseResultMap"  type="com.talent.service.dto.NentsukiShuKanriMasterDto" autoMapping="true">
    <result column="NENTSUKI" jdbcType="INTEGER" property="nentsuki" />
    <result column="SHU" jdbcType="INTEGER" property="shu" />
    <result column="SHU_FROM" jdbcType="DATE" property="shuFrom" />
    <result column="SHU_TO" jdbcType="DATE" property="shuTo" />
    <result column="TOROKU_DAY" jdbcType="TIMESTAMP" property="torokuDay" />
    <result column="KOUSHIN_DAY" jdbcType="TIMESTAMP" property="koushinDay" />
  </resultMap>
```
※resultMapで指定している通り、上記では結果とするDTOの形は「NentsukiShuKanriMasterDto」とMappingさせるようにしている。
autoMapping="true"にすることで自動的に取得した結果を設定される。

###  （２）タグ「select」
⇒今回は、自動生成時に作られるもの。（mybatis-generator-config.xmlの「table」タグの設定にもよる）
基本的には対象のMapper XML用のテーブルからのみのSELECT文を記載する。（結合などにより取得することもできるが、今回は単テーブル用のMapperクラスのため）
SQLの条件として使用するパラメータについてはselectタグに指定する。
・parameterTypeでパラメータのデータ型、resultMapで戻りのMappingの形を参照する。上記で紹介したBaseResultMapの形に合わせる。

```java:MNentsukiShuKanriMapper.xml　（例）
  <select id="select" parameterType="string" resultMap="BaseResultMap">
	   select
	     TALENT_ID
	    ,TALENT_NAME
	    ,GENRE_ID
	    ,DELETE_FLG
	    ,TOROKU_DAY
	    ,KOUSHIN_DAY
	   from
	    M_TALENT
       where
       1 = 1 
       and DELETE_FLG = '0'
      <if test="talentId != ''"> 
      	and TALENT_ID =#{talentId,jdbcType=VARCHAR}
      </if>
      <if test="talentName != ''"> 
      	and TALENT_NAME LIKE CONCAT('%', #{talentName,jdbcType=VARCHAR}, '%')
      </if>
  </select>
```
パラメータの内容の有無の条件を分岐させる件について
→条件は<if test="">の形で分岐させる。

###  （３）タグ「insert」
⇒selectと同様に自動生成で作られることもでき、基本的には対象のMapper XML用のテーブルからのみのINSERT文を記載する。VALUEは呼び出し元のパラメータを記載しています。

```java:MNentsukiShuKanriMapper.xml　（例）
  <insert id="insert" parameterType="com.model.MTalent">
    insert into M_TALENT (TALENT_ID, TALENT_NAME, GENRE_ID, DELETE_FLG, TOROKU_DAY, KOUSHIN_DAY)
    values (#{talentId,jdbcType=VARCHAR}, #{talentName,jdbcType=VARCHAR}, #{genreId,jdbcType=INTEGER}, 
      #{deleteFlg,jdbcType=INTEGER}, #{torokuDay,jdbcType=TIMESTAMP}, #{koushinDay,jdbcType=TIMESTAMP})
  </insert>
```

###   （４）タグ「update」
⇒selectと同様に自動生成で作られることもでき、基本的には対象のMapper XML用のテーブルからのみのUPDATE文を記載する。各列の更新値は呼び出し元のパラメータを記載しています。

```java:MNentsukiShuKanriMapper.xml
  <update id="update" parameterType="com.model.MTalent">
     update M_TALENT set
      TALENT_NAME = #{talentName,jdbcType=VARCHAR},
      GENRE_ID = #{genreId,jdbcType=INTEGER},
      KOUSHIN_DAY = #{koushinDay,jdbcType=TIMESTAMP}
     WHERE
      TALENT_ID = #{talentId,jdbcType=VARCHAR}
  </update>
```
###   （５）タグ「delete」
⇒selectと同様に自動生成で作られることもでき、基本的には対象のMapper XML用のテーブルからのみのDELETE文を記載する。WHEREの条件値は呼び出し元のパラメータを記載しています。

```java:MNentsukiShuKanriMapper.xml
  <delete id="delete" parameterType="string" >
     delete from M_TALENT WHERE TALENT_ID = #{talentId,jdbcType=VARCHAR}
  </delete>
```
###   （６）Mapper XMLの全文
以下、（１）～（５）を盛り込んだ全文を掲載します。

```java:MNentsukiShuKanriMapper.xml

<?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.talent.infrastructure.repository.mapper.generated.MNentsukiShuKanriMapper">
  <resultMap id="BaseResultMap"  type="com.talent.service.dto.NentsukiShuKanriMasterDto" autoMapping="true">
    <result column="NENTSUKI" jdbcType="INTEGER" property="nentsuki" />
    <result column="SHU" jdbcType="INTEGER" property="shu" />
    <result column="SHU_FROM" jdbcType="DATE" property="shuFrom" />
    <result column="SHU_TO" jdbcType="DATE" property="shuTo" />
    <result column="TOROKU_DAY" jdbcType="TIMESTAMP" property="torokuDay" />
    <result column="KOUSHIN_DAY" jdbcType="TIMESTAMP" property="koushinDay" />
  </resultMap>
  <select id="select" parameterType="integer" resultMap="BaseResultMap">
       select 
       	 NENTSUKI
       	,SHU
       	,SHU_FROM
       	,SHU_TO
       	,TOROKU_DAY
       	,KOUSHIN_DAY
       from 
       	M_NENTSUKI_SHU_KANRI 
       where 
        1 = 1
       	<if test="nentsuki != null"> 
      	 and NENTSUKI = #{nentsuki,jdbcType=INTEGER} 
       	</if>
       	<if test="shu != null"> 
      	 and SHU = #{shu,jdbcType=INTEGER}
       	</if>
  </select>
  <select id="selectAll" resultMap="BaseResultMap">
       select 
       	 NENTSUKI
       	,SHU
       	,SHU_FROM
       	,SHU_TO
       	,TOROKU_DAY
       	,KOUSHIN_DAY
       from 
       	M_NENTSUKI_SHU_KANRI 
  </select>
 <insert id="insert" parameterType="com.model.MNentsukiShuKanri">
    insert into M_NENTSUKI_SHU_KANRI (NENTSUKI, SHU, SHU_FROM, SHU_TO, TOROKU_DAY, KOUSHIN_DAY)
    values (#{nentsuki,jdbcType=INTEGER}, #{shu,jdbcType=INTEGER}, #{shuFrom,jdbcType=DATE}, 
      #{shuTo,jdbcType=DATE}, #{torokuDay,jdbcType=TIMESTAMP}, #{koushinDay,jdbcType=TIMESTAMP})
  </insert>
  <update id="update" parameterType="com.model.MNentsukiShuKanri">
     update M_NENTSUKI_SHU_KANRI set
      SHU_FROM = #{shuFrom,jdbcType=DATE},
      SHU_TO = #{shuTo,jdbcType=DATE},
      KOUSHIN_DAY = #{koushinDay,jdbcType=TIMESTAMP}
     WHERE
      NENTSUKI = #{nentsuki,jdbcType=INTEGER} and
      SHU = #{shu,jdbcType=INTEGER}
  </update>
  <delete id="delete" parameterType="string" >
     delete from M_TALENT WHERE TALENT_ID = #{talentId,jdbcType=VARCHAR}
  </delete>
</mapper>
```

### 各SQLの自動設定の箇所について
自動設定でどのようなものを作成するかは、「mybatis-generator-config.xml」に、
以下のように記載しています。各設定の使い方はここでは割愛します。

```java:mybatis-generator-config.xml
    <!-- 自動生成するテーブルの設定 -->
    <table tableName="%"
      enableInsert="true"
      enableSelectByPrimaryKey="true"
      enableUpdateByPrimaryKey="true"
      enableDeleteByPrimaryKey="true"
      enableSelectByExample="false"
      enableUpdateByExample="false"
      enableDeleteByExample="false"
      enableCountByExample="false"
      selectByPrimaryKeyQueryId="false"
      selectByExampleQueryId="false"
      modelType="flat">
    </table>
```

## 3.呼び出し元のMapperのスーパークラスの紹介
以下、MNentsukiShuKanriMapper.xmlの各SQLを実行時のスーパークラスとなります。
以下のように呼び出しをしております。


```java:MNentsukiShuKanriMapper.java

package com.talent.infrastructure.repository.mapper.generated;
import java.util.List;

import org.apache.ibatis.annotations.Mapper;

import com.model.MNentsukiShuKanri;
import com.talent.service.dto.NentsukiShuKanriMasterDto;

@Mapper
public interface MNentsukiShuKanriMapper {

	List<NentsukiShuKanriMasterDto> select(Integer nentsuki, Integer shu);
	
	List<NentsukiShuKanriMasterDto> selectAll();

	int insert(MNentsukiShuKanri mNentsukiShuKanri);

	int update(MNentsukiShuKanri mNentsukiShuKanri);

	int delete(String talentId);
}
```

## 4.まとめ
上記は自動生成したものを書き変えた例なので再度自動生成をすると上書きされて消えてしまいます。
そのため、自動生成はしたものを派生させて、作る方が健全です。
以下はシンプルに「各SQLの自動設定の箇所について」の設定で
自動生成させたのみの「MNentsukiShuKanriMapper.xml」と、
派生させた「MNentsukiShuKanriMapperEx.xml」（もともと書いていたMNentsukiShuKanriMapper.xmlの内容を設定）の例です。

```java:MNentsukiShuKanriMapper.xml
<?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.talent.infrastructure.repository.mapper.generated.MNentsukiShuKanriMapper">
  <resultMap id="BaseResultMap" type="com.talent.infrastructure.repository.model.generated.MNentsukiShuKanri">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Dec 03 16:17:02 JST 2023.
    -->
    <result column="NENTSUKI" jdbcType="INTEGER" property="nentsuki" />
    <result column="SHU" jdbcType="INTEGER" property="shu" />
    <result column="SHU_FROM" jdbcType="DATE" property="shuFrom" />
    <result column="SHU_TO" jdbcType="DATE" property="shuTo" />
    <result column="TOROKU_DAY" jdbcType="TIMESTAMP" property="torokuDay" />
    <result column="KOUSHIN_DAY" jdbcType="TIMESTAMP" property="koushinDay" />
  </resultMap>
  <insert id="insert" parameterType="com.talent.infrastructure.repository.model.generated.MNentsukiShuKanri">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Dec 03 16:17:02 JST 2023.
    -->
    insert into M_NENTSUKI_SHU_KANRI (NENTSUKI, SHU, SHU_FROM, 
      SHU_TO, TOROKU_DAY, KOUSHIN_DAY
      )
    values (#{nentsuki,jdbcType=INTEGER}, #{shu,jdbcType=INTEGER}, #{shuFrom,jdbcType=DATE}, 
      #{shuTo,jdbcType=DATE}, #{torokuDay,jdbcType=TIMESTAMP}, #{koushinDay,jdbcType=TIMESTAMP}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.talent.infrastructure.repository.model.generated.MNentsukiShuKanri">
    <!--
      WARNING - @mbg.generated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Sun Dec 03 16:17:02 JST 2023.
    -->
    insert into M_NENTSUKI_SHU_KANRI
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="nentsuki != null">
        NENTSUKI,
      </if>
      <if test="shu != null">
        SHU,
      </if>
      <if test="shuFrom != null">
        SHU_FROM,
      </if>
      <if test="shuTo != null">
        SHU_TO,
      </if>
      <if test="torokuDay != null">
        TOROKU_DAY,
      </if>
      <if test="koushinDay != null">
        KOUSHIN_DAY,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="nentsuki != null">
        #{nentsuki,jdbcType=INTEGER},
      </if>
      <if test="shu != null">
        #{shu,jdbcType=INTEGER},
      </if>
      <if test="shuFrom != null">
        #{shuFrom,jdbcType=DATE},
      </if>
      <if test="shuTo != null">
        #{shuTo,jdbcType=DATE},
      </if>
      <if test="torokuDay != null">
        #{torokuDay,jdbcType=TIMESTAMP},
      </if>
      <if test="koushinDay != null">
        #{koushinDay,jdbcType=TIMESTAMP},
      </if>
    </trim>
  </insert>
  <resultMap autoMapping="true" id="BaseResultMap" type="com.talent.service.dto.NentsukiShuKanriMasterDto">
    <result column="NENTSUKI" jdbcType="INTEGER" property="nentsuki" />
    <result column="SHU" jdbcType="INTEGER" property="shu" />
    <result column="SHU_FROM" jdbcType="DATE" property="shuFrom" />
    <result column="SHU_TO" jdbcType="DATE" property="shuTo" />
    <result column="TOROKU_DAY" jdbcType="TIMESTAMP" property="torokuDay" />
    <result column="KOUSHIN_DAY" jdbcType="TIMESTAMP" property="koushinDay" />
  </resultMap>
  <select id="select" parameterType="integer" resultMap="BaseResultMap">
       select 
       	 NENTSUKI
       	,SHU
       	,SHU_FROM
       	,SHU_TO
       	,TOROKU_DAY
       	,KOUSHIN_DAY
       from 
       	M_NENTSUKI_SHU_KANRI 
       where 
        1 = 1
       	<if test="nentsuki != null"> 
      	 and NENTSUKI = #{nentsuki,jdbcType=INTEGER} 
       	</if>
       	<if test="shu != null"> 
      	 and SHU = #{shu,jdbcType=INTEGER}
       	</if>
  </select>
  <select id="selectAll" resultMap="BaseResultMap">
       select 
       	 NENTSUKI
       	,SHU
       	,SHU_FROM
       	,SHU_TO
       	,TOROKU_DAY
       	,KOUSHIN_DAY
       from 
       	M_NENTSUKI_SHU_KANRI 
  </select>
 <insert id="insert" parameterType="com.model.MNentsukiShuKanri">
    insert into M_NENTSUKI_SHU_KANRI (NENTSUKI, SHU, SHU_FROM, SHU_TO, TOROKU_DAY, KOUSHIN_DAY)
    values (#{nentsuki,jdbcType=INTEGER}, #{shu,jdbcType=INTEGER}, #{shuFrom,jdbcType=DATE}, 
      #{shuTo,jdbcType=DATE}, #{torokuDay,jdbcType=TIMESTAMP}, #{koushinDay,jdbcType=TIMESTAMP})
  </insert>
  <update id="update" parameterType="com.model.MNentsukiShuKanri">
     update M_NENTSUKI_SHU_KANRI set
      SHU_FROM = #{shuFrom,jdbcType=DATE},
      SHU_TO = #{shuTo,jdbcType=DATE},
      KOUSHIN_DAY = #{koushinDay,jdbcType=TIMESTAMP}
     WHERE
      NENTSUKI = #{nentsuki,jdbcType=INTEGER} and
      SHU = #{shu,jdbcType=INTEGER}
  </update>
</mapper>
```
```java:MNentsukiShuKanriMapperEx.xml
 ※ （6） Mapper XMLの全文
```

## 5.終わりに
少し長くずらずら書いてしまい備忘録寄りになりましたが、自動生成でSQLをしてくれるのはすごく便利ですね。
何か加えた条件があれば拡張ファイルを作って作れば再度の自動生成も問題ないため上手く使い分けたいですね。また何かあれば書きます。

よいクリスマスかつ年末年始をお過ごしください。