はじめに
Spring BootでJPAを用いたとき、違和感を感じるほど簡単に条件を絞ることができる。
例えば特定のidを持つdataをtableから取得するためには
クエリ文なら、select * from table where id = 1
と表記するが、
JPAで、findById(1)
などと表記する。
しかし、こういったわかりやすい表記を用いることで、かえってより細かい条件まで絞ることに限界が生じてしまう。
よってそれを解決するために、クエリ文を用いて条件を絞ることを少しまとめる。
Code
Entity
@Entity
@Data
@Table(name = "accounts")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
@Column(name = "login_id")
private String loginId;
@Column(name = "login_pw")
private String loginPw;
@Column(name = "is_admin")
private Boolean isAdmin = false;
}
Repositry
public interface AccountRepository extends JpaRepository<Account, Integer> {
@Query("select a from Account a")
List<Account> findByidQuery();
@Query("select a from Account a where a.id = ?1")
Account findByidQueryOne(Integer id);
@Query("select a from Account a where a.isAdmin = false ")
List<Account> findByidQueryNotAdmin();
}
注意しないといけないのは、クエリ文だからSQLと全く同じようなTable名、Column名を使用してはいけない。
SQLでのColumn名はis_admin
であるが、JPAで利用するためにはEntityと同じ名前であるisAdmin
として表記しなければいけない。
Controller
@Controller
@RequestMapping("/account")
public class AccountController {
@Autowired
AccountRepository accountRepository;
@GetMapping("/query")
public String queryTest() {
List<Account> accounts = accountRepository.findByidQuery();
Account account = accountRepository.findByidQueryOne(1);
List<Account> accountsNotAdmin = accountRepository.findByidQueryNotAdmin();
// Repositoryからクエリ文によるaccountを取得した
return "account/index";
}
}
その他
public interface ReadingRecordRepository extends JpaRepository<ReadingRecord, Integer> {
@Query("select new com.example.demo.model.Recommend(rr.itemId, count(rr.itemId)) "
+ "from ReadingRecord rr "
+ "where rr.itemRelatedId = ?1 "
+ "group by rr.itemId order by count(rr.itemId) desc "
+ "limit 5")
List<Recommend> findRecommends(Integer itemRelatedId);
}
より複雑な組み合わせであると、上のように書くことができる。
閲覧記録(ReadingRecord)から関連アイテムの記録をカウントして、上位5つのRecommendを取得するようにした。
Entityにないような型だと、modelを作成してnew ~ model.Model(id, name)
などとして型を指定しなければならない。
おわりに
少し特殊な形、例えばCount
、Sum
などの集計的な内容があるとき、クエリ文を使用することがほぼ必須であると思われる。Modelを作成して型指定をすることも必要である。
個人的にはJPAをそのまま利用するよりも、クエリ文で書いたほうがよりしっくりくるのでより好んで利用すると思った。