1
4

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 3 years have passed since last update.

Spring Data JPAでの検索クエリ

Posted at

Spring Data JPAを利用した検索クエリの作成に苦戦したので、
メモを残します。以下、掲載内容です。

  • JPAを用いたデータアクセス
  • JPQLのクエリ
  • Where句の動的条件
  • Where句の動的条件+Select句のDistict

JPAとは

Java Persistence API 関係データベースのデータを扱う Java SE および Java EE のアプリケーションを開発するためのJava用フレームワークである。
出典:ウィキペディア

自分の解釈では

  • Entityでデータ構造、データの関係性を定義
  • クエリはJPQL(Java Persistence Query Language)で作ろう

ということだと思います。

Spring Data

SpringBootのデータアクセスフレームワーク
Spring Data JDBCSpring Data JPAなど様々なデータアクセスが用意されています。

Spring Data JPAの利用方法

早速、使っていきたいと思います。
先ずはpom.xmlの指定

pom.xml
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

データアクセスはEntityとRepositoryを用意してアクセスします。

TUser.java

@Entity
@Table(name = "T_USER ")
public class TUser {

    @Id
    String userId;
    String userNo;
    String userName;
    String email;
    // …
    // + Getter&Setter
}
TUserRepository.java

@Repository
public interface TUserRepository extends JpaRepository<TUser, String>,
        JpaSpecificationExecutor<TUser>, TUserRepositoryCustom {
// @QueryによるJPQLなど
}

JpaRepositoryの継承で基本的なデータアクセスが可能です。
@Queryの指定でJPQLによるクエリも実行可能です。

TUserRepository.java
<S extends T> S save(S entity);        // 保存
Optional<T> findById(ID primaryKey);   // 単一検索条件
Iterable<T> findAll();                 // 全Select
long count();                          // count
void delete(T entity);                 // delete
boolean existsById(ID primaryKey);     // exists

// JPQL文による検索条件指定のクエリ
@Query("select u from TUser u where u.email= ?1")  
User findByEmail(String email);

ここまでだとWhere句に動的な条件を付与できない為、
JpaSpecificationExecutorを継承し、
findAll(Specification)に検索条件を渡します。
独自の条件を生成する関数を用意し、呼び出し元のサービスクラスから
findAll()の引数に指定すると動的条件の付与が可能です。

TUserRepository.java
// 独自条件生成の関数 userNameに値が設定されている場合のみ、条件を生成する。
static Specification<TUser> userNameContains(String userName) {
  return StringUtils.isEmpty(userName) ? null : new Specification<TUser>() {
      @Override
      public Predicate toPredicate(Root<TUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
        return cb.like(root.get("userName"), "%" + userName + "%");
      }
   };
}

サービスクラス
@Autowired
TUserRepository rep;

public List<TUser> getList(String userName) {
  List<TUser> list = rep.findAll(Specification
    .where(TUserRepository.userNameContains(userName));
    // 複数項目の場合は.and(),.or()でつなげる
}

Where句に動的条件を付与しつつ、select句をdistinctする場合は
TUserRepositoryCustomという独自のinterfaceを用意し、
EntiyManager,CriteriaBuilderでクエリを作成します。
XXXReposytory Customとつけるのがルールのようです。

TUserRepositoryCustomImpl.java
  @Autowired
  private JpaContext context;

  public List<String> findBySpec(Specification<TUser> spec) {
    final EntityManager em = context.getEntityManagerByManagedType(TUser.class);
    // CriteriaBuilderでクエリを作成
    final CriteriaBuilder cb = em.getCriteriaBuilder();
    // CriteriaQueryに設定するObjectを指定 ※戻り値になる。
    CriteriaQuery<String> query = cb.createQuery(String.class);
    // FROM句
    Root<TUser> root = query.from(TUser.class);
    // select句
    query.select(root.get("userId")).distinct(true);
    // where句 ※外部指定可能にしている
    query.where(spec.toPredicate(root, query, cb));
    final List<String> resultList = em.createQuery(query).getResultList();

    return resultList;
  }
}
サービスクラス
@Autowired
TUserRepository rep;

public List<TUser> getList(String userName) {
  List<String> list = rep.findBySpec(Specification
    .where(TUserRepository.userNameContains(userName));
}

まとめ

最近は複雑なクエリを実行する機会は少ないかもしれませんが、
どうしようもない時もSpring Data JPAでは手法が用意されていました。

これからは複雑なクエリが生まれないように
シンプルなデータアクセスを意識したDB設計が重要だと感じました。

参考

Spring Data JPA - リファレンスドキュメント
[Java][Spring Boot] Customクラスを使用してデータベースアクセスする

1
4
0

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
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?