[Java][Spring Boot] Criteria APIでJavaらしくデータベースを検索。

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

これまでのJPQLに関する記事は、クエリを"from MyData where id = :id"の様に文字で書いていました。
SQLをほぼそのままなので分かりやすいと言えばそうなのですが、Javaとしてどうなのかと言われると疑問です。
EclipseなどのIDEの自動エラーチェックにも引っかからないので、スペルミスでコンパイルが通らなくて原因解明に時間を取られる...なんて事は無くしたいです。
そこで今回は、JPAが実装しているCriteria APIを使用して、Javaらしいクエリの作成と実行を試してみたいと思います。

環境

Mac OSX 10.10.5 Yosemite
Eclipse Mars2
Java 8
Spring Boot 1.3.6
PostgreSQL 9.5.1

テーブル準備

PostgreSQLで作成しました。

CREATE TABLE fruit (
    id VARCHAR(2) NOT NULL,
    name VARCHAR(10),
    price integer,
    PRIMARY KEY(id)
);

INSERT INTO fruit VALUES
  ('1','apple',300),
  ('2','orange',200),
  ('3','banana',100),
  ('4','cherry',100),
  ('5','pineapple',500),
  ('6','melon',800),
  ('7','watermelon',600),
  ('8','strawberry',450)
  ;
postgres=# select * from fruit ;
 id |    name    | price 
----+------------+-------
 1  | apple      |   300
 2  | orange     |   200
 3  | banana     |   100
 4  | cherry     |    50
 5  | pineapple  |   500
 6  | melon      |   800
 7  | watermelon |   600
 8  | strawberry |   450
(8 rows)

コード

エンティティ

package com.jpa.mydao;

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

import lombok.Data;

@Entity
@Data
@Table(name="fruit")
public class Fruit {

	@Id
	private String id;
	private String name;
	private Integer price;

}

今回もlombokの@DataでGetter/Setterを生成しています。

DAOインターフェース

package com.jpa.mydao.dao;

import java.io.Serializable;
import java.util.List;

public interface FruitDao <T> extends Serializable {
	public List<T> getAll();
}

DAOオブジェクト

package com.jpa.mydao.dao;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Repository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.jpa.mydao.Fruit;

@Repository
public class FruitDaoJpql implements FruitDao<Fruit>{

	private EntityManager entityManager;

	public FruitDaoJpql() {
	}

	public FruitDaoJpql(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	@Override
	public List<Fruit> getAll() {
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
		CriteriaQuery<Fruit> query = builder.createQuery(Fruit.class);
		Root<Fruit> root = query.from(Fruit.class);
		query.select(root);
		List<Fruit> list = (List<Fruit>) entityManager.createQuery(query).getResultList();
		return list;
	}

}

基本の流れは下記になっている様です。
builder -> query -> root -> メソッド実行 -> 結果を取得

29~37行目はDAOインターフェースで作成したメソッドです。
31行目、CriteriaBuilder。クエリ生成の管理クラス。
32行目、CriteriaQuery。クエリ実行のクラス。
33行目、Root。ここからエンティティの絞り込みなどを行います。
34行目、クエリの生成。テーブル検索の準備完了です。
35行目、クエリを実行してListで取得。
SQLだと、"select * from fruit;"となります。

コントローラー

package com.jpa.mydao;

import java.util.List;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import com.jpa.mydao.dao.FruitDaoJpql;

@RestController
public class EntityManagerController {

	@PersistenceContext
	EntityManager entityManager;

	FruitDaoJpql dao;
	
	@PostConstruct
	public void init() {
		dao = new FruitDaoJpql(entityManager);
	}
	
	@RequestMapping(value="/all", method=RequestMethod.GET)
	public List<Fruit> all() {
		List<Fruit> list = dao.getAll(); 
		return list;
	}

}

"http://localhost:8080/all"で呼ばれるメソッドが一つだけです。
30行目、DAOオブジェクトからgetAll()を実行してListで取得しています。

実行

$ curl http://localhost:8080/all
[{"id":"1","name":"apple","price":300},{"id":"2","name":"orange","price":200},{"id":"3","name":"banana","price":100},{"id":"4","name":"cherry","price":50},{"id":"5","name":"pineapple","price":500},{"id":"6","name":"melon","price":800},{"id":"7","name":"watermelon","price":600},{"id":"8","name":"strawberry","price":450}]

さいごに

SQLが読めれば、後は処理の流れを覚えるだけで良さそうです。
次回は、より詳細な検索を試してみたいと思います。