440
449

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Spring Data JPA でのクエリー実装方法まとめ

Last updated at Posted at 2014-08-03

Spring Data JPA でクエリーを実装する方法をざっくりまとめてみた。

JPAのクエリー実装方法

先ずはJPAのクエリー実装方法を見てみる。
JPAでは EntityManage を使用してクエリーを構築/実行するが、主な実装方法は以下の通り。

  • ネイティブSQL
  • JPQL
  • CriteriaAPI
  • 名前付きクエリー
  • JPAプロバイダの機能を直接使用する

ネイティブSQL

EntityManager#createNativeQuery(String)を使用する。

        List<User> results = entityManager
            .createNativeQuery("select * from user where name = :name", User.class)
            .setParameter("name", "きい太")
            .getResultList();

JPQL

EntityManager#createQuery(String)を使用する。

        List<User> results = entityManager
                .createQuery("from User where name = :name", User.class)
                .setParameter("name", "きい太")
                .getResultList();

CriteriaAPI

EntityManager#createQuery(CriteriaQuery)を使用する。

        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<User> query = cb.createQuery(User.class);
        Root<User> root = query.from(User.class);
        query.where(cb.equal(root.get("name"), "きい太"));
        List<User> results = entityManager
                .createQuery(query)
                .getResultList();

名前付きクエリー

@NamedQuery 又は @NamedNativeQuery を使用してEntityクラスに名前付きクエリーを定義しておく事ができる。
定義した名前付きクエリーはEntityManager#createNamedQuery(String)で使用する。

User.java
@Entity
@NamedQuery(name = "findByName", query = "from User where name = :name")
public class User {
}
        List<User> results = entityManager
                .createNamedQuery("findByName", User.class)
                .setParameter("name", "きい太")
                .getResultList();

JPAプロバイダの機能を直接使用する

EntityManager#unwrap()でJPAプロバイダ(Hibernate,EclipseLinkeなど)のオブジェクトを取得して実装する。

Hibernateの場合
        Session session = entityManager.unwrap(Session.class);
        :

Spring Data JPA のクエリー実装方法

Spring Data JPA では Repositoryインターフェイスにメソッドを定義することでクエリーが作成される。

UserRepository.java
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
    public User findByName(String name);
    public User findByEmail(String email);
    :

Repositoryのスーパーインターフェイスには以下が用意されている。

  • org.springframework.data.repository.CrudRepository
    • org.springframework.data.repository.PagingAndSortingRepository
      • org.springframework.data.jpa.repository.JpaRepository
  • org.springframework.data.jpa.repository.JpaSpecificationExecutor

JpaRepositoryには標準的なCRUD操作を行うメソッドが用意されている。
通常はJpaRepositoryだけ使用すれば良いが、後述のSpecificationを使用する場合はJpaSpecificationExecutorも併用する。

標準のメソッド以外のクエリーを作るには、Repositoryインターフェイスにクエリーメソッドを追加する。
クエリーメソッドの実装方法は以下の通り。

  • 命名規約に従ったメソッド名での自動実装
  • @Queryアノテーションでのクエリー指定
  • リポジトリ実装クラスでクエリーを実装する
  • Specificationでの実装

命名規約に従ったメソッド名での自動実装

決められたパターンでメソッド名を定義すると、クエリーを指定しなくても自動実装される。

UserRepository.java
    public List<User> findByNameContainsOrderByIdAsc(String name);
実行されるJPQL
select u
from User u
where u.name like %:name%
order by u.id asc

@Queryアノテーションでのクエリー指定

複雑なクエリーや、命名規約ではメソッド名が長くなってしまう場合などには、@QueryアノテーションでJPQL又はネイティブSQLを指定して任意のメソッド名でクエリーを定義する事ができる。

UserRepository.java
    @Query("select u from User u where u.name like %:name% order by u.id asc")
    public List<User> findUsers(@Param("name") String name);

名前付きクエリーの指定

@Queryのname属性でEntityクラスに定義した名前付きクエリーと結び付ける事ができる。

User.java
@Entity
@NamedQuery(name = "findUsers", query = "select u from User u where u.name like %:name% order by u.id asc")
public class User {
UserRepository.java
    @Query(name = "findUsers")
    public List<User> findByNamedQuery(@Param("name") String name);

が、せっかくRepositoryにクエリーをまとめてるのにEntityクラスにクエリーを書くという事はないので、Spring Data JPA で名前付きクエリーを使う際はプロパティファイルを使用する。

プロパティファイルに名前付きクエリーを定義する

クエリー名はデフォルトではEntity名.メソッド名となるが、@Queryのname属性で変更可能。

resources/META-INF/jpa-named-queries.properties
User.findAllOrderByName=select u from User u order by u.name
User.findAllOrderByEmailDesc=select u from User u order by u.email desc
UserRepository.java
    public List<User> findAllOrderByName();
    @Query(name = "User.findAllOrderByEmailDesc")
    public List<User> findAllOrderByEmail();

リポジトリ実装クラスでクエリーを実装する

動的クエリーの組み立てやJPAプロバイダの機能を使用する場合など、特殊なクエリーが必要な場合等には自分でクエリーメソッドを実装する事ができる。

UserRepository.java
public interface UserRepository extends 
        JpaRepository<User, Long>,
        JpaSpecificationExecutor<User>,
        UserRepositoryCustom {
UserRepositoryCustom.java
public interface UserRepositoryCustom {
    public List<User> findUsers(String name, String email);
}
UserRepositoryImpl.java
public class UserRepositoryImpl implements UserRepositoryCustom {
    @Autowired
    EntityManager entityManager;
    public List<User> findUsers(String name, String email) {
        //ここにクエリーを実装する
    }
}

Specification

Specificationは何らかの検索条件を表すインターフェイスで、CriteriaAPIを使用して検索条件を実装する。

UserSpecifications.java
    public Specification<User> nameContains(String name) {
        return StringUtils.isEmpty(name) ? null : (root, query, cb) -> {
            return cb.like(root.get("name"), "%" + name + "%");
        };
    }
    public Specification<User> emailContains(String email) {
        return StringUtils.isEmpty(email) ? null : (root, query, cb) -> {
            return cb.like(root.get("email"), "%" + email + "%");
        };
    }
呼び出す箇所
    List<User> results = userRepository.findAll(Specifications
        .where(nameContains(name))
        .and(emailContains(email))
    );
440
449
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
440
449

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?