【 Spring 】H2 データベースを使用した Repository のテストで Like を使用した部分が動かない問題
Spring を使ったアプリケーションでデータアクセス部分のテストをする時 DbSetUp + H2 DB を使うことが良くある( というかそれしか使ったことない気も )のですがその際に表題の問題に直面したので残しておきます。
前提
今回 Spring で DB アクセセスがあるアプリケーションを実装していました。
Repository 部分は Spring Data Jpa と Specification を使っています。( やっていることはこちらで紹介されている方法とほぼ同じです。 )
public Specification nameContain(String searchName) {
return searchName == null ? null : (root, query, builder) -> builder.like(root.get("name"),
searchName + "%"
);
}
テストではざっくり以下の様に H2 DB に DbSetUp でデータを Insert している形です。
private final Operation INSERT = Operations.insertInto("SAMPLE")
.row()
.column("NO", "1")
.column("NAME","John")
h2 の設定はこんな感じ
spring:
datasource:
driverClassName: org.h2.Driver
url: jdbc:h2:mem:testoracledb;MODE=Oracle;DB_CLOSE_DELAY=-1;
username: username
password: password
これに対して jpa の findAll などを以下の様に行いこちらをテスト ( 要は SampleSpecification のロジックをテスト ) しているという状況です。
SampleSpecification specification = new SampleSpecification();
Specification query = Specification.where(specification.nameContain("Jo"))
List<SampleEntity> user = target.findAll(query);
問題
上記でテストを行った際に specification の Like を使った条件、つまり上記の nameContain だけがうまく動かずデータを取得できませんでした。
nameContain メソッドを以下の様に equal に変更して イコールになる条件を指定した場合は動くため Like 句だけの問題の様でした。
public Specification nameContain(String searchName) {
return searchName == null ? null : (root, query, builder) -> builder.equal(root.get("name"),
searchName
);
}
解決策
調べたところこれは h2-database を oracle compatibility mode で使った際に出るバグとの情報がこちらにありました。
本番環境が Oracle の DB だった事もあり上記の通り今回は MODE=Oracle でテストをしておりその場合に Like を使うというピンポイントな条件でした。
解決策としては以下の様にエスケープ用の文字を入れるとの対応がありましたが、このテストのためだけに本番のコードを変更することをあまりしたくなかったのもあり今回は MODE=Oracle を辞めることで対応しました。
builder.like(root.get("name"), searchName + "%", '\\')
一応上記でも正しく動くことは確認しております。
最後に
こちらのバグは割とピンポイントだった事もあり日本語の記事なども無さそうだったので一応残しておいた形になります。 Hibernate ORM 自体のバグとの事でしたが、それを最初に疑ってかかる事はしなかったため割と時間を持って行かれてしまいました、、、
ディスカッション
コメント一覧
まだ、コメントがありません