5
Mar 2024
by
健雄 尹
Spring Data Jpaが提供する機能を調べてみよう
Query Methodの三つの機能
- メソッド名前でクエリ作成
- メソッド名前でJPA NamedQuery呼び出し
@Queryアノテーションを使いレポジトリインタフェースに直接クエリを定義
メソッド名前でクエリ作成
Spring Data JPAがメソッドの名前を分析してJPQLクエリを実行してくれる。
注意点:
エンティティの名前が変更されると必ずインタフェースに定義したメソッドの名前も一緒に変更する必要がある、そうでないとアプリケーションを立ち上げる時点でエラーが生じる。こうやってアプリケーションのロード時にエラーを検知できるのがSpring Data JPAのすごく大きい長所である。
純粋なJPA Repositoryの場合
- ユーザの名前と歳(age)でユーザを検索する場合
public List<User> findByUsernameAndAgeGreaterThan(String username, int age) {
return em.createQuery("select u from User u where u.username = :username
and m.age > :age")
.setParameter("username", username)
.setParameter("age", age)
.getResultList();
}メソッド名前でクエリ生成機能の場合
- Spring Data JPAはメソッドの名前を分析しJPQLを生成して実行してくれる。
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsernameAndAgeGreaterThan(String username, int age);
}詳しくはこちらを参照:https://docs.spring.io/spring-data/jpa/reference/jpa/query-methods.html
Spring Data JPAが基本的に提供してくれるQuery Method機能
- 照会:
find...By,read...By,query...By,get...By...にはクエリを説明する内容が入っても良い
- カウント:
count...By- 返り値のタイプ :
long
- 返り値のタイプ :
- EXISTS:
exists...By- 返り値のタイプ :
boolean
- 返り値のタイプ :
- 削除:
`delete...By`, `remove...By`- 返り値のタイプ :
long
- 返り値のタイプ :
- DISTINCT:
`findDistinct`, `findUserDistinctBy` - LIMIT:
`findFirst2`, `findFirst`, `findTop`, `findTop3`
JPA NamedQuery
JPAのNamedQueryを呼び出せる機能である。
まずNamedQueryを定義する
@Entity
@NamedQuery(
name="User.findByUsername",
query="select u from User u where u.username = :username"
)
public class Uesr {
...
}JPAを直接使いNamedQueryを呼び出す方法
public class UserRepository {
public List<User> findByUsername(String username) {
...
List<User> resultList =
em.createNamedQuery("User.findByUsername", User.class)
}
}Spring Data JPAでNamedQueryを呼び出す方法
@Query(name = "User.findByUsername")
List<User> findByUsername(@Param("username") String username);@Queryを省略してメソッドの名前だけでNamedQueryを呼び出すこともできる。
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByUsername(@Param("username") String username);
}- Spring Data JPAは定義した
ドメインクラス + .(period) + メソッド名前を組み合わせNamedQueryを探して実行してくれる。 - もし実行するNamedQueryがないと上で説明した「**メソッド名前でクエリ作成**」戦略を使用する。
@Query, レポジトリメソッドにQueryを定義する
メソッドにJPQLクエリを作成
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.username= :username and u.age = :age")
List<User> findUser(@Param("username") String username, @Param("age") int age);
}@Queryアノテーションをしよする- Spring Data JPAが提供するのか要確認
- JPA NamedQueryみたいにアプリケーション実行時にSyntax Errorとかを検知できる。
- すごく良い長所である。
値、DTO照会
単純照会
@Query(select u.username from User u) List<User> findUsernameList();
- JPAの
@Embeddedがついたタイプもこの方式で照会できる。
DTOで直接照会
@Query("select new jp.co.tagbangers.UserDto(u.id, u.username, t.name) " +
"from User u join u.team t")
List<UserDto> findUserDto();- DTOで直接照会するためにはJPAの
new命令語を使う必要がある。 - コンストラクタが用意されている必要がある。
@Data
public class UserDto {
private Long id;
private String username;
private String teamName;
public UserDto(Long id, String username, String teamName) {
this.id = id;
this.username = username;
this.teamName = teamName;
}
}Parameter Binding
- 順番方式
- 名前方式
select m from Member m where m.username = ?0 // 順番 select m from Member m where m.username = :name // 名前
なるべく名前方式を使うのをお勧めする。順番をミスして入れると大変なバグになる可能性が高い。
import org.springframework.data.repository.query.Param
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.username = :name")
User findUser(@Param("name") String username);
}Collection Parameter Binding
inをサポートする
@Query("select u from User u where u.username in :names")
List<User> findByNames(@Param("names") List<String> names);変換タイプ
Spring Data JPAは柔軟な変換タイプをサポートする
List<User> findByUsername(String name); // Collection
- 照会結果がない場合Empty Collectionを返す
User findByUsername(String name); // Select
- 照会結果がない場合
Nullを返す - 結果が2件以上だったら
javax.persistence.NonUniqueResultException例外を発生する。
Optional<User> findByUsername(String name); // Optional
