JPAによるQuerydslのガイド

1概要

Querydslは広範なJavaフレームワークであり、SQL に似たドメイン固有の言語で 型安全なクエリを作成および実行するのに役立ちます。

この記事では、Java Persistence APIを使用したQuerydslについて説明します。

ここでのちょっとした注意はHibernateのためのHQLがQuerydslのための最初のターゲット言語でしたが、最近ではバックエンドとしてJPA、JDO、JDBC、Lucene、Hibernate検索、MongoDB、コレクションとRDFBeanをサポートします。

2準備

まず、必要な依存関係をMavenプロジェクトに追加しましょう。

<properties>
    <querydsl.version>2.5.0</querydsl.version>
</properties>

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-apt</artifactId>
    <version>${querydsl.version}</version>
    <scope>provided</scope>
</dependency>

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-jpa</artifactId>
    <version>${querydsl.version}</version>
</dependency>

<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.6.1</version>
</dependency>

それでは、Maven APTプラグインを設定しましょう。

<project>
    <build>
    <plugins>
    ...
    <plugin>
        <groupId>com.mysema.maven</groupId>
        <artifactId>apt-maven-plugin</artifactId>
        <version>1.1.3</version>
        <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
        </executions>
    </plugin>
    ...
    </plugins>
    </build>
</project>

JPAAnnotationProcessor は、 javax.persistence.Entity アノテーションが付けられたドメインタイプを見つけて、それらのクエリータイプを生成します。

3 Querydsl によるクエリ

クエリは、ドメインタイプのプロパティを反映して生成されたクエリタイプに基づいて構築されます。また、関数/メソッドの呼び出しは、完全に型保証された方法で構築されています。

クエリのパスと操作はすべての実装で同じです。また、 Query インタフェースにも共通の基本インタフェースがあります。

** 3.1. エンティティとQuerydslクエリタイプ

**

例を見ながら、最初に使用する単純なエンティティを定義しましょう。

@Entity
public class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String firstname;

    @Column
    private String surname;

    Person() {
    }

    public Person(String firstname, String surname) {
        this.firstname = firstname;
        this.surname = surname;
    }

   //standard getters and setters

}

Querydslは、単純な名前 QPerson を持つクエリタイプを Person と同じパッケージに生成します。 QPerson は、 Person タイプの代表として、Querydslクエリで静的に型指定された変数として使用できます。

まず - QPerson には静的フィールドとしてアクセスできるデフォルトのインスタンス変数があります。

QPerson person = QPerson.person;

あるいは、このようにあなた自身の Person 変数を定義することができます。

QPerson person = new QPerson("Erich", "Gamma");

3.2. JPAQuery を使用してクエリを作成する

クエリに JPAQuery インスタンスを使用できるようになりました。

JPAQuery query = new JPAQuery(entityManager);

entityManager はJPAの EntityManager です。

簡単な例として、名前が " Kent "のすべての人物を取得しましょう。

QPerson person = QPerson.person;
List<Person> persons = query.from(person).where(person.firstName.eq("Kent")).list(person);

from 呼び出しはクエリソースと射影を定義し、 where 部分はフィルタを定義し、 list は一致したすべての要素を返すようにQuerydslに指示します。

複数のフィルタを使用することもできます。

query.from(person).where(person.firstName.eq("Kent"), person.surname.eq("Beck"));

または

query.from(person).where(person.firstName.eq("Kent").and(person.surname.eq("Beck")));

ネイティブJPQL形式では、クエリは次のようになります。

select person from Person as person where person.firstName = "Kent" and person.surname = "Beck"

「or」を使ってフィルタを組み合わせる場合は、次のパターンを使用します。

query.from(person).where(person.firstName.eq("Kent").or(person.surname.eq("Beck")));

** 4 Querydslにおける順序付けと集約

**

それでは、Querydslライブラリ内で順序付けと集計がどのように機能するかを見てみましょう。

4.1. ご注文

結果を surname フィールドの降順に並べることから始めます。

QPerson person = QPerson.person;
List<Person> persons = query.from(person)
    .where(person.firstname.eq(firstname))
    .orderBy(person.surname.desc())
    .list(person);

4.2. 集計

利用可能なものがいくつかあるので(Sum、Avg、Max、Min)、単純な集計を使用しましょう。

QPerson person = QPerson.person;
int maxAge = query.from(person).list(person.age.max()).get(0);

** 4.3. GroupBy による集約

**

com.mysema.query.group.GroupBy クラスは、クエリ結果をメモリに集約するために使用できる集約機能を提供します。

これは、結果として firstname をキーとして、 max age を値として Map として返される簡単な例です。

QPerson person = QPerson.person;
Map<String, Integer> results =
  query.from(person).transform(
      GroupBy.groupBy(person.firstname).as(GroupBy.max(person.age)));

** 5 Querydslによるテスト

**

それでは、Querydslを使用してDAO実装を定義しましょう - そして、次の検索操作を定義しましょう:

public List<Person> findPersonsByFirstnameQuerydsl(String firstname) {
    JPAQuery query = new JPAQuery(em);
    QPerson person = QPerson.person;
    return query.from(person).where(person.firstname.eq(firstname)).list(person);
}

それでは、この新しいDAOを使用していくつかのテストを作成し、Querydslを使用して( PersonDao クラスに実装された)新しく作成された Person オブジェクトを検索し、 GroupBy クラスを使用した別のテスト集約でテストします。

@Autowired
private PersonDao personDao;

@Test
public void givenExistingPersons__whenFindingPersonByFirstName__thenFound() {
    personDao.save(new Person("Erich", "Gamma"));
    Person person = new Person("Kent", "Beck");
    personDao.save(person);
    personDao.save(new Person("Ralph", "Johnson"));

    Person personFromDb =  personDao.findPersonsByFirstnameQuerydsl("Kent").get(0);
    Assert.assertEquals(person.getId(), personFromDb.getId());
}

@Test
public void givenExistingPersons__whenFindingMaxAgeByName__thenFound() {
    personDao.save(new Person("Kent", "Gamma", 20));
    personDao.save(new Person("Ralph", "Johnson", 35));
    personDao.save(new Person("Kent", "Zivago", 30));

    Map<String, Integer> maxAge = personDao.findMaxAgeByName();
    Assert.assertTrue(maxAge.size() == 2);
    Assert.assertSame(35, maxAge.get("Ralph"));
    Assert.assertSame(30, maxAge.get("Kent"));
}

6. 結論

このチュートリアルでは、Querydslを使ってJPAプロジェクトをビルドする方法を説明しました。

この記事の 完全な実装 はhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/querydsl[githubプロジェクト]にあります - これはEclipseベースのMavenプロジェクトです。そのままインポートして実行するのは簡単です。

ここでの簡単なメモは - 単純なMavenビルド(mvn clean install)を実行して target/generated-sources に型を生成し、そしてEclipseを使用している場合はそのフォルダをプロジェクトのソースフォルダとして含めます。