JPAによるQuerydslのガイド

JPAを使用したQuerydslガイド

1. 概要

Querydslは、type-safe queries in a domain specific language that is similar to SQLの作成と実行に役立つ広範なJavaフレームワークです。

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

ここで簡単な注意点として、HibernateのHQLはQuerydslの最初のターゲット言語でしたが、最近ではJPA、JDO、JDBC、Lucene、Hibernate Search、MongoDB、Collections、RDFBeanをバックエンドとしてサポートしています。

2. 準備する

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


    2.5.0



    com.querydsl
    querydsl-apt
    ${querydsl.version}
    provided



    com.querydsl
    querydsl-jpa
    ${querydsl.version}



    org.slf4j
    slf4j-log4j12
    1.6.1

それでは、MavenAPTプラグインを構成しましょう。


    
    
    ...
    
        com.mysema.maven
        apt-maven-plugin
        1.1.3
        
        
            
                process
            
            
                target/generated-sources
                com.querydsl.apt.jpa.JPAAnnotationProcessor
            
        
        
    
    ...
    
    

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はJPAEntityManagerであることに注意してください。

簡単な例として、名が「Kent」のすべての人を取得してみましょう。

QPerson person = QPerson.person;
List 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"));

Or:

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"

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

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

4. Querydslでの順序付けと集約

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

4.1. ご注文

まず、結果をsurnameフィールドの降順で並べ替えます。

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

4.2. 集約

利用可能なものがいくつかあるので(合計、平均、最大、最小)、単純な集計を使用してみましょう。

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

4.3. GroupByによる集約

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

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

QPerson person = QPerson.person;
Map results =
  query.from(person).transform(
      GroupBy.groupBy(person.firstname).as(GroupBy.max(person.age)));

5. Querydslを使用したテスト

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

public List 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を使用して新しく作成されたPersonオブジェクト(PersonDaoクラスで実装)を検索し、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 maxAge = personDao.findMaxAgeByName();
    Assert.assertTrue(maxAge.size() == 2);
    Assert.assertSame(35, maxAge.get("Ralph"));
    Assert.assertSame(30, maxAge.get("Kent"));
}

6. 結論

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

この記事のfull implementationin the github projectにあります–これはEclipseベースのMavenプロジェクトであるため、そのままインポートして実行するのは簡単です。

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