Eclipse+JSF+JPAで作るアプリ(18)―JPA Criteria API
やりたいことは、前回作った検索画面で、タイトル、カテゴリ、あらすじの3つのフィールドでnullまたは空白だったら無視をして、ANDの検索条件を動的に作ることです。
JPQLのパラメータでは、固定のパラメータとなるため、APIを使って条件に応じたクエリを実装する必要があるはずです。(JPQLの文字列を動的に作成するという方法も、もちろんあります。)
実際の業務アプリケーションでは、
- 検索条件のオペレーターを「含む」、「=」、「始まりが一致する」「終わりが一致する」など指定できる
- 空白で区切られた複数のキーワードをORで結合して検索できる
- 動的に検索するフィールドを追加できる
などの機能が必要になるかもしれませんが、今回の実装では、紹介のみで、そこまでは含みません。
Criteria APIを使ったsearchMovieメソッド
searchMovieの仕様は次の通りです。
- 画面で入力された、title, category, outlineをand条件にした検索を行っています。
- 値が空(nullもしくは、isEmptyがtrue)の場合は、条件から外しています。
- すべて空だった場合はすべて検索します。
先に全体の実装を載せて、各部分ごとに説明していきます。
ちなみに、criteria(クライテリア)はcriterion(クライテリオン)の複数形で、判定基準(の複数形)という意味です。
MovieManager.javaのsearchMovieの実装
public static List<Movie> searchMovie(String title, String category, String outline) { EntityManager em = getEm(); CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Movie> query = cb.createQuery(Movie.class); Root<Movie> root = query.from(Movie.class); query.select(root); List<Predicate> predicates = new ArrayList<Predicate>(); if( title != null && !title.isEmpty() ) { predicates.add( cb.like(root.get("title"), "%" + title + "%") ); } if( category != null && !category.isEmpty() ) { predicates.add( cb.equal(root.get("category"), category) ); } if( outline != null && !outline.isEmpty() ) { predicates.add( cb.like(root.get("outline"), "%" + outline + "%") ); } if( predicates.size() > 0 ) { query.where(cb.and(predicates.toArray(new Predicate[]{}))); } query.orderBy(cb.asc(root.get("title"))); return em.createQuery(query).getResultList(); }
それでは各パーツを見ていきます。
CriteriaBuilder の作成
CriteriaBuilder cb = em.getCriteriaBuilder();
- CriteriaBuilderというクエリのビルダをEntityManagerから取得します。
CriteriaQuery の作成
CriteriaQuery<Movie> query = cb.createQuery(Movie.class);
CriteriaQuery のAPI
Root<Movie> root = query.from(Movie.class); query.select(root); query.where(cb.and(predicates.toArray(new Predicate[]{}))); query.orderBy(cb.asc(root.get("title")));
Predicate 検索条件クラス
predicates.add( cb.like(root.get("title"), "%" + title + "%") ); predicates.add( cb.equal(root.get("category"), category) );
- CriteriaBuilder(ビルダ)クラスから「オペレータAPI名(属性名,条件値)」という形式で検索条件を作成します。
- 上のwhere句でCreiteriaBuilder#and APIでリストに追加された検索条件をandで結合しています。
- root.get(フィールド名)の箇所は、Metamodel (クラス名_, Movie_など)を作成することで型安全性を上げることができます。
Metamodelについての説明ははじめての Java Persistence API | 寺田 佳央 - Yoshio Teradaを参照ください。
MetamodelのGeneratorは、java - How to generate JPA 2.0 metamodel? - Stack Overflowを参照ください。
以上が各部分の説明です。