エンタープライズギークス (Enterprise Geeks)

企業システムの企画・開発に携わる技術者集団のブログです。開発言語やフレームワークなどアプリケーション開発に関する各種情報を発信しています。ウルシステムズのエンジニア有志が運営しています。

JavaEE7をはじめよう(7) - Querydslとストアドプロシージャ

前回までの3回の記事で、JPAが提供する3つのクエリの定義方法を紹介した。
今回はJPAクエリの番外編として、Querydslとストアドプロシージャを紹介する。

Querydslの概要

Querydsl は様々なクエリを生成するためのDSLライクなAPIを提供するオープンソースJavaライブラリである。

SQLJPAクエリーの他、mongoDBや Javaコレクションなどに対しても、Querydslを通してデータ抽出や加工を行うことができる。

Querydslでは、JPAのCriteria APIに対しても、それをラップする形で使いやすいAPIを提供している。

以下では、Querydsl JPAのgithubを参考に、pom.xmlにライブラリの依存性とAPT実行の定義を行ってみる*1

サンプル1(動的なwhere句)

前回の記事で紹介した、2つの可変なwhere条件の例をQueryDSL JPA で書き直すと以下のようになる。

// Member型の型変数を用意
QMember m = QMember.member;
// 動的な条件の生成
BooleanExpression preds = null;
if (name != null && number != null) {
    preds = m.name.like(name + "%")
            .and(m.playerNumber.eq(number));
} else if(name != null) {
    preds = m.name.like(name + "%");
} else {
    preds = m.playerNumber.eq(number);
}

// JPAQueryをEntityMangerから生成
JPAQuery q = new JPAQuery(em);

// クエリの実行
List<Member> list = 
 q.from(m)
    .where(preds)
    .orderBy(m.member.id.asc())
    .list(m); // Selectは最後に指定。

Querydsl JPA のライブラリを設定してビルドを行うと、エンティティクラスごとに Q +<エンティティクラス名> という名前で型変数と呼ばれるクラスが APT によって生成される。

APT (Annotation processing tool)は、コンパイル時にアノテーションによって任意の処理をコンパイル処理中に組み込む仕組みで、今回の場合では、@Entity が付いたクラスを対象に、型変数クラスを生成している。

利用するクラスは、型変数と JPAQueryのみである。 型変数自体が、eq, like, asc などのWhere句やOrderBy句の式に該当するメソッドを持ち、 andなどを使用してメソッドチェーンでクエリ全体の生成ができるため、SQLに近い記述が可能となっている。

前回紹介したCriteria APIによるプログラムと比べると、明らかにシンプルになっていることが読み取れるだろう。

サンプル2(Join, コンストラクタ式)

続いて、 Joinや、コンストラクタ式を使用した例も書き直すと、次のようになる。

QTeam t = QTeam.team;
QMember m = QMember.member;

JPAQuery q = new JPAQuery(em);
List<TeamSummary> res =
    q.from(t).join(t.members, m)
     .groupBy(t.name, t.id)
     .list(ConstructorExpression.create(
        TeamSummary.class, t.name, t.count()));

こちらも、SQLに近い記述になっていることが読み取れるだろう。

ストアドプロシージャの実行

さて、JPAの最後として、ストアドプロシージャ対応について簡単に触れておく。
古いバージョンのJPAではNativeQueryを使用する必要があったが、JPA 2.1からストアドプロシージャを実行するメソッドが追加された。

サンプルコード

ストアドプロシージャを実行するサンプルコードは以下のようになる。

StoredProcedureQuery sq = em.createStoredProcedureQuery("procA");
sq.registerStoredProcedureParameter("param1", 
                        Integer.class, ParameterMode.IN);
sq.registerStoredProcedureParameter("param2", 
                        String.class, ParameterMode.IN);
sq.registerStoredProcedureParameter("result", 
                        Integer.class, ParameterMode.OUT);

sq.setParameter("param1", 100);
sq.setParameter("param2", "test");
sq.execute();

Integer result = (Integer)sq.getOutputParameterValue("result");

ここでは、StoredProcedureQueryを作成してから、プロシージャ名(procA)とIN引数(param1, param2)、OUT引数(result)を設定し、プロシージャを実行後に OUT引数を取得している。特に難しい所はないだろう。

まとめ

4回にわたって、JPAのクエリの実行方法について紹介した。

次回は、JPAを採用した場合のIDの定義方法について議論する。

[前多 賢太郎]

*1:2015年2月時点の最新バージョンの3.6.1において、上記公式ページに記載されているグループIDとパッケージが間違っており、com.querydslをcom.mysema.queryに読み替える必要があった。