【Javaお勉強日記】mybatisを使って独自クラスとカラムに対して複雑なマッピングをする
必要になったのでまとめます。
0.サービスを作る
// BookService.java
public class BookService{
BookRepository bookRepository;
public BookService(BookRepository bookRepository){
this.bookRepository = bookRepository;
}
// 中略...
public Book getBookDataByCode(String bookCode){
return bookRepository.selectBookDataByCode(bookCode);
}
}
図書管理アプリを作る想定。サービスから、Stringで冊子コードを渡してリポジトリを呼ぶようにしておきます。関連データをひとまとまりにして返したいので、戻り値はBook型にしておきます。
サービス側の挙動としては「getしてくる」、だけど、リポジトリ側の挙動は「SQL使ってselectする」なので、リポジトリ側のメソッドはselectと命名することにしてみます。その辺りはお好みとかプロジェクトの宗教によって。
1.戻り値を入れるためのBookクラスを用意する
サービスからまとめて返したいデータ=DBから取得したいカラムと同じフィールドを持つクラスを作る。
//Book.java
import lombok.Data
@Data
public class Book{
String id;
String title;
String author;
int price;
}
lombok.Dataをインポートして、クラスに@Dataを付与しておけば、面倒なことは裏で全部やってくれるので、最低限これだけ書いておけばOK。
特に事情が無ければ、DBのカラム名と一致するように作って置くと後々が楽。だけど、DBのカラム名がhoge_hugaみたいにスネークケースとかhoge-hugaみたいなケバブケースで、変数名はhogeHugaとキャメルケースに統一したい、みたいな場合はあとでマッピングできるので統一しなくてもよい。
2.リポジトリインターフェイスにメソッドを宣言する
前回といっしょ。戻り値の型だけBookに変更。
// BookRepository.java
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BookRepository {
Book selectBookDataByCode(String bookCode);
}
戻り値をBookにするためにBook型のインポートも必要なので忘れずに。
3.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.project.application.repository.book.BookRepository">
<select id="selectBookDataByCode" resultType="com.project.domain.model.Book" parameterType="string">
SELECT
id,
title,
author,
price
FROM sample.database
WHERE bookcode = #{bookcode}
</select>
</mapper>
とりあえずSELECT文を書く。SELECTするカラムはBookクラスのフィールドが持っているものだけにする。
今回は、ResultTypeを指定して、結果がBookクラスに入るようにする。独自クラスをResultTypeに指定する場合、importする時に使うのと同じアドレスをべたっと書く。
DBのカラム名と戻り値型のフィールド名が全て一致している場合は、これだけで裏で勝手にマッピングしてくれる。
4.ResultMapを作る
DBのカラム名とフィールド名が一致しないとか、DBにはコードで入っている情報を、別のテーブル参照して日本語に戻してから追加したいとか、そういう一手間が必要な場合、XMLファイル内にResultMapを定義しておいて、手動でマッピングする。
<!-- <mapper>内部に -->
<resultMap id="bookMap" type="com.project.domain.model.Book" >
<result property="title" column="title" />
<result property="autherName" column="auther_name" />
<result property="price" column="price" />
<association property="publisher" column="publisher_code" javaType="string" select="_findPublisherName" />
</resultMap>
<select id="__findPublisherName" parameterType="string" resultType="string">
SELECT
publisher_name
FROM
publisher
WHERE
publisher_id = {#publisher_id}
</select>
例えば、出版社の情報は、DBにはコードだけで入れておいて、表示する時に出版社テーブルから日本語名を持ってこよう、という実装になっている場合。
<association>タグを使うことで、別のselect文の結果をさらに取ってくることができる。javaTypeはstringとかintとかlong辺りのプリミティブ型は用意されてるのでそのまま入れられるし、独自クラスを用意してもいい。
で、本命のSELECT文を書いてあるselectタグのresultType属性の代わりに、resultMap="resultMapId"を使えば、このマッピングを適用して結果を受け取ることができる。
5.検索結果をListで受け取る
検索結果が複数件になる場合、勝手にListにして渡してくれる。便利。
その場合も、ResultTypeは一件当たりのデータを入れる用の型を書けば良い。(Stringだけの1列×複数行を取得するなら、resultType="String"にしておけば、戻り値は自動でList<String>になる)
6.パラメータをリストで渡す
// BookRepository.java
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface BookRepository {
List<Book> selectBookDatasByMultipulCodes(List<String> bookCodes);
}
リポジトリ側で、引数の型をList<String>型で宣言しておく。
XML側では、
<select id="selectBookDatasByMultipulCodes" resultType="com.project.domain.model.Book" parameterType="list">
SELECT
id,
title,
author,
price
FROM sample.database
WHERE bookcode in
<foreach item="bookCodes" collection="list" open="(" separator="," close=")">
#{bookCodes}
</foreach>
</select>
てな具合に、parameterTypeをlistにして、foreachタグを使ってリストの中身を全部取り出して使う。
さらに、Mapとか、オブジェクトとかの、キーと値のペアが格納されているものを引数で渡した場合、
#{object.key}
を使えばvalueを使える。
この記事が気に入ったらサポートをしてみませんか?