SEワンタンの独学備忘録

独学した内容や資格試験に対する取り組みの備忘録

【MyBatis】MyBatis@Springで動的なSQLを発行する際に発生したエラー対応

大したことではないはずだけどエラーで異常につまったので備忘録

アプリそのものには価値や意味はないんだけど、javaのサンプルアプリを作成しておきたかったのでせっかくなので以前導入したTERASOLUNA(Spring)を使用してみたときの話。
DB接続にはMyBatisを使用する構成で、動的なSQLを作りたくなったんです。

プロジェクトの構成

画像だと見にくいけどプロジェクトの構成はこんな感じ。

f:id:wantanBlog:20190917223032p:plain

UserListRepository.xmlの実装

元々の静的SQL

元々は以下のようなホントに単純に全件取得するのみのSQLでした。

<?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属性に、Repositoryインタフェースの完全修飾クラス名(FQCN)を指定する。 -->
<mapper namespace="com.example.todoMyBatis.domain.repository.userList.UserListRepository">

    <!-- <resultMap>要素に、検索結果(ResultSet)とJavaBeanのマッピング定義を行う。 -->
    <resultMap id="userListResultMap" type="UserDto">
        <id property="userId" column="user_id" />
        <result property="userName" column="user_name" />
        <result property="deleteFlg" column="delete_flg" />
    </resultMap>

    <!-- 中略 -->

    <!-- 全件のユーザを取得する -->
    <select id="findAll"  resultMap="userListResultMap">
        SELECT
            user_id,
            user_Name,
            delete_flg
        FROM
            m_user
        ORDER BY user_id
    </select>
動的SQL

元のSQLから「deleteFlgが検索条件に設定されているかによってSQLの検索条件を変更したくなった。
「deleteFlg」=1の場合は全件検索、それ以外の場合はdelete_flg=0のレコードのみ検索する。
※書いてて思ったけどflgが反転していてあんまりいい実装じゃないかも

xxxRepository.xmlのSQL自体の動的な書き方はすぐわかって以下のように修正を加えた。

    <!-- 全レコードを取得するSQLを実装している。 -->
    <select id="findAll" parameterType="String" resultMap="userListResultMap">
        SELECT
            user_id,
            user_Name,
            delete_flg
        FROM
            m_user
		<where>
	  	<if test="deleteFlg != 1">
    		delete_flg = 0
  		</if>
  		</where>
        ORDER BY user_id
    </select>

パラメータを一つ追加したいので以下を追記。複数の場合は検索条件Dtoみたいなのを実装した方がきれいかも

parameterType="String"

deleteFlgの値によって検索条件を動的に書き換えたいので以下を追記

<if test="deleteFlg != 1">
delete_flg = 0
</if>

検索条件を動的にした結果、WHERE句自体が消える場合があるので以下のように記述

<where>
 <!-- 中略(条件)-->
</where>

エラー内容

とりあえず上記で実行するとこのSQLが走る際に以下のようなエラーが発生した。

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'deleteFlg' in 'class java.lang.String'

パラメータの名前がうまく認識されていないみたい??
なぜかここでつまっていろいろ試す羽目になった。

UserListRepository.javaの実装(対策)

エラーが発生した元々の実装

結果としては、サービスから呼び出され、UserListRepository.xmlを呼び出す「UserListRepository.java」の実装に問題があったようです。
エラーが発生していたときは以下のように記述していました。

public interface UserListRepository {

	/**
	 * userListの全件取得
	 */
	Collection<UserDto> findAll(String deleteFlg);

  	//中略
}
エラーが解消した実装

対策としてはなんてことはない、パラメータ名を明示してあげただけ。
確かに知らなきゃできないけど、検索すればすぐにわかりそうなものだがなんであんなにハマったんだろう。。

import org.apache.ibatis.annotations.Param;

public interface UserListRepository {

	/**
	 * userListの全件取得
	 */
	Collection<UserDto> findAll(@Param("deleteFlg") String deleteFlg);

  	//中略
}


具体的には全件検索を行うfindAllメソッドの引数(パラメータ)に@Param("deleteFlg")を追加しただけです。

後は、ないとコンパイルエラーになるからハマるところでもないんだけどParamアノテーションを使用するために以下のインポートを追加しています。

import org.apache.ibatis.annotations.Param;


これだけで解決。ほんとになんでハマったんだ
単に検索条件として使用する際などの#{deleteFlg}みたいのは特にパラメータ名を明示しなくても拾ってくれるみたいなのは勉強不足のため理由は謎、参照仕方が違ったりするんだろうか。

ちなみにパラメータ名を認識させるには、この対応方法だけではなく他の実装方法もあるみたいです。

おまけ 実装した画面

初期表示

f:id:wantanBlog:20190917231005p:plain

検索実行時

f:id:wantanBlog:20190917231033p:plain


問題ないので雑だけど終わりです。