JPAのCriteriaBuilderでRDBMSの関数を使う

DBでは数値として持った値を、左0埋めして画面に表示していたが、そこを文字列として部分一致検索させることになった。

検索はSpringのSpecificationで、動的なJPQLをCriteriaBuilderで組み立てており、RDBMSの関数を使えないか調べたのでメモ。

やりたいこと

DB(MySQL)では数値で保存した値を左ゼロ埋めし、接頭語をつけて表示している。

数値が1なら、表示は NUM00001 というイメージ。

これを文字列として、部分一致検索できるようにしたい。

対応

MySQLであればLPAD関数で0埋めし、それを接頭語と CONCAT すればいい。

CONCAT に対応する操作はCriteriaBuilder#concatで行える。

RDBMSの関数を、JPQLで実行できるか調べたところ、JPA Criteriaで左埋めできないかというそのまんまな質問が、Stack Overflowにあった。

stackoverflow.com

CriteriaBuilder#functionを使えば、RDBMSの関数の実行ができる。

第1引数が関数名、第2引数が関数の戻り値の型、それ以降は可変長引数で関数に渡す値を指定する。

注意点としては、可変長引数の型はExpressionのため、リテラルCriteriaBuilder#literalでExpressionに変換してやる必要がある。

// 左ゼロ埋めを実施
var leftPad = cb.function(
        "LPAD",
        String.class,
        root.get(ExampleEntity_.seq).as(String.class),
        cb.literal(5),
        cb.literal("0")
);

// 接頭語とCONCAT
var displayValue = cb.concat("NUM", leftPad);

// CONCATした文字列を、部分一致検索
cb.like(displayValue, "%" + inputValue + "%")

振り返り

SQL Serverを除いた主要なRDBMSではLPADが使えるようだが、可搬性は下がるので、JPQLの使い方としてはやや邪道か。

DBのテーブル側にカラムを追加して、文字列として保存しておくのが無難かなとは思う。

とはいえ、必要に応じて関数を実行できるようになっているのはありがたい。