MyBatis Dynamic SQLで柔軟なORマッピング実装をしてみた

# MyBatis Dynamic SQLを使ってみよう！

今回はMyBatis Dynamic SQLを使ってSQLを発行し、データを取得する実装を試してみました！

業務でバリバリ使うことになるかもなので、備忘録として残しておきます。
実装形式としてはSeasar2のS2JDBCに似ていて、複数のメソッドチェインを行うことで発行するSQLを作成しています。

## 実行準備

用意したテーブルはこんな感じでシンプルなものを用意しました。
データはテキトーに数件登録しておきます。

```sql
CREATE TABLE "MEMBER" ( 
  "ID" NUMBER(8,0)
  , "BLOOD" VARCHAR2(20 BYTE)
  , "NAME" VARCHAR2(20 BYTE)
  , "CORP" VARCHAR2(20 BYTE)
);
```

Entityもテーブル構成に合わせて作成します。

```java
public class Member {
	
	private Integer id;
	
	private String name;
	
	private String corp;
	
	private String blood;
	
    //getter・setterは省略

}
```

マッパーインターフェースは下記のように作成します。
今回は複数のデータをListに返却する想定で実装しています。

```java
public interface MemberMapper {

	@SelectProvider(type=SqlProviderAdapter.class, method="select")
	@Results(id="memberResult", value={
		@Result(column="ID", property="id"),
		@Result(column="NAME", property="name"),
		@Result(column="CORP", property="corp"),
		@Result(column="BLOOD", property="blood"),
	})
	List<Member> selectMany(SelectStatementProvider selectStatement);

}
```

MyBatis Dynamic SQLと連携するためのサポートクラスを作成します。
取得するカラムやWHERE句の指定をするときなどに利用します。

```java
public final class MemberDynamicSqlSupport {

	public static final Member Member = new Member();

	public static final SqlColumn <Integer> id = Member.id;
	public static final SqlColumn <String> name = Member.name;
	public static final SqlColumn <String> corp = Member.corp;
	public static final SqlColumn <String> blood = Member.blood;


	public static final class Member extends SqlTable {
		public final SqlColumn <Integer> id = column("ID", JDBCType.INTEGER);
		public final SqlColumn <String> name = column("NAME", JDBCType.VARCHAR);
		public final SqlColumn <String> corp = column("CORP", JDBCType.VARCHAR);
		public final SqlColumn <String> blood = column("BLOOD", JDBCType.VARCHAR);

		public Member() {
			super("Member");
		}
	}

}
```

## SQL実行

上記で作成したクラスを使って実際にSQLを発行するクラスを実装してみましょう。
今回はjunitを使ってテストコードを実装してみます。

```java
import static jp.co.stylez.support.MemberDynamicSqlSupport.*;
import static org.mybatis.dynamic.sql.SqlBuilder.isEqualTo;
import static org.mybatis.dynamic.sql.SqlBuilder.isLessThan;
import static org.mybatis.dynamic.sql.SqlBuilder.select;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MybatisConfig.class)
public class Main {

	@Autowired
	ApplicationContext context;

	@Test
	public void test() {

		MemberMapper mapper = context.getBean(MemberMapper.class);

		SelectStatementProvider selectStatement = select(Member.allColumns()).from(Member).where(id, isLessThan(10))
				.and(corp, isEqualTo("stylez")).orderBy(id).build().render(RenderingStrategies.MYBATIS3);

		List<Member> members = mapper.selectMany(selectStatement);

		for (Member member : members) {
			System.out.println("********************");
			System.out.println("id：" + member.getId());
			System.out.println("name：" + member.getName());
			System.out.println("corp：" + member.getCorp());
			System.out.println("blood：" + member.getBlood());
			System.out.println("********************");
		}
	}

}
```

Configクラスは別途実装してDataSourceやMapperScan対象の設定をしておきます。
XML形式でも設定可能ですが、今回はJavaで設定しました。
(設定関連の解説は割愛します)

MapperScanで登録したMapperを取り出し、実際にSQLを実行しています。

実行結果は下記のようになります。

```
********************
id：1
name：hogehoge
corp：stylez
blood：B
********************
********************
id：2
name：test.taro
corp：stylez
blood：O
********************
********************
id：3
name：hiroya.endo
corp：stylez
blood：A
********************
```

指定した条件のデータが複数取得出来ていることが確認できました！

## 実際に使ってみて…

主にWHERE句の条件指定に関して非常に柔軟な実装が可能だと感じました。
コードの可読性としても非常に高く、コーティングもしやすいので使いやすい印象でした。

テーブル結合やサブクエリにも対応できるので、それもまた魅力の一つかと思いました。
Mapper.xmlを使用したSQLと使い分けることも可能なので、必要に応じて構成管理ができると思います。

これから使う方のよい参考になれば幸いです！


## 参考

https://github.com/mybatis/mybatis-dynamic-sql

https://mybatis.org/mybatis-dynamic-sql/docs/conditions.html