如何在 JPA 中將 findBy() 與多列一起使用
一、簡介
Spring Dat;u JPA提供了查詢派生功能,使用該功能我們只需遵循方法名稱約定即可自動派生查詢。
在本文中,我們將使用查詢衍生功能透過一列或多列來尋找實體。
2. 設定範例
出於範例目的,我們將使用包含與使用者帳戶相關的屬性的Account
實體:
@Entity
@Table(name = "ACCOUNTS")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accounts_seq")
@SequenceGenerator(name = "accounts_seq", sequenceName = "accounts_seq", allocationSize = 1)
@Column(name = "user_id")
private int userId;
private String username;
private String password;
private String email;
private Timestamp createdOn;
private Timestamp lastLogin;
@OneToOne
@JoinColumn(name = "permissions_id")
private Permission permission;
// getters and setters
}
出於演示目的,我們還將在Accounts
表中添加一些範例資料:
使用者身分 | 使用者名稱 | 密碼 | 電子郵件 | 創建於 | 上次登入 | 允許 |
---|---|---|---|---|---|---|
1 | 使用者管理員 | 737d4251-7ccf-46ce-8227-24cce9be812e | [電子郵件受保護] | 2024-02-08 21:26:30.372286 | 2024-02-09 21:26:30.37229 | 編輯 |
2 | 使用者_管理員_1 | 65cfd915-240c-4f64-8378-27fa1ff9cdf5 | [電子郵件受保護] | 2024-02-06 21:26:30.372286 | 2024-02-07 21:26:30.37229 | 編輯 |
3 | 使用者管理員_2 | 9b4dca2e-f1d2-4b14-9553-3b8913323b48 | [電子郵件受保護] | 2024-02-04 21:26:30.372286 | 2024-02-06 21:26:30.37229 | 編輯 |
3. 查詢推導
查詢派生允許開發人員在儲存庫介面中定義遵循命名約定的方法名稱,並且框架根據該方法名稱產生適當的查詢。
例如,如果我們想透過電子郵件地址搜尋accounts
表,那麼我們在AccountRepository
中的方法將如下所示:
public interface AccountRepository extends JpaRepository<Account, Integer> {
Account findByEmail(String email);
}
如果我們在 AccountRepository 上執行findByEmail()
AccountRepository,
Spring Data 會產生以下 SQL 並針對accounts
表執行它:
select a1_0.user_id,a1_0.created_on,a1_0.email,a1_0.last_login,a1_0.password,a1_0.permissions_id,a1_0.username
from accounts a1_0
where a1_0.email=?
我們的測試驗證了findByEmail() :
@Test
void givenAccountInDb_whenPerformFindByEmail_thenReturnsAccount() {
String email = "[email protected]";
Account account = accountRepository.findByEmail(email);
assertThat(account.getEmail()).isEqualTo(email);
}
4. 多列的findBy()
我們可以擴展查詢派生功能以新增條件組合以獲得適當的結果。
讓我們使用AccountRepository
介面並編寫另一種方法來尋找具有username
和email
Accounts:
public interface AccountRepository extends JpaRepository<Account, Integer> {
Account findByUsernameAndEmail(String username, String email);
}
以下是為定義的方法所產生的 SQL:
select a1_0.user_id,a1_0.created_on,a1_0.email,a1_0.last_login,a1_0.password,a1_0.permissions_id,a1_0.username
from accounts a1_0
where a1_0.username=? and a1_0.email=?
我們的測試驗證了findByUsernameAndEmail():
@Test
void givenAccountInDb_whenPerformFindByUsernameAndEmail_thenReturnsAccount(){
String email = "[email protected]";
String username = "user_admin";
Account account = accountRepository.findByUsernameAndEmail(username, email);
assertThat(account.getUsername()).isEqualTo(username);
assertThat(account.getEmail()).isEqualTo(email);
}
我們也可以使用OR
運算子來組合兩個條件。例如,我們可以透過username
或email
進行搜尋:
public interface AccountRepository extends JpaRepository<Account, Integer> {
Account findByUsernameOrEmail(String username, String email);
}
讓我們來看看產生的 SQL:
select a1_0.user_id,a1_0.created_on,a1_0.email,a1_0.last_login,a1_0.password,a1_0.permissions_id,a1_0.username
from accounts a1_0
where a1_0.username=? or a1_0.email=?
現在,讓我們驗證findByUsernameOrEmail():
@Test
void givenAccountInDb_whenPerformFindByUsernameOrEmail_thenReturnsAccount(){
String email = "[email protected]";
String username = "user_editor";
Account account = accountRepository.findByUsernameOrEmail(username, email);
assertThat(account.getUsername()).isNotEqualTo(username);
assertThat(account.getEmail()).isEqualTo(email);
}
我們可以在findBy()
方法中使用輸入集合。例如,要尋找電子郵件清單或使用者名稱清單中存在的所有帳戶,我們可以在AccountRepository
中編寫一個方法:
public interface AccountRepository extends JpaRepository<Account, Integer> {
List<Account> findByUsernameInOrEmailIn(List<String> usernames, List<String> emails);
}
讓我們來看看產生的 SQL:
select a1_0.user_id,a1_0.created_on,a1_0.email,a1_0.last_login,a1_0.password,a1_0.permissions_id,a1_0.username
from accounts a1_0
where a1_0.username in (?,?) or a1_0.email in (?,?,?)
我們的測試證實了findByUsernameInOrEmailIn()
的工作原理:
@Test
void givenAccountInDb_whenPerformFindByUsernameInOrEmailIn_thenReturnsAccounts(){
List<String> emails = List.of("[email protected]", "[email protected]", "[email protected]");
List<String> usernames = List.of("user_editor", "user_admin");
List<Account> byUsernameInOrEmailIn = accountRepository.findByUsernameInOrEmailIn(usernames, emails);
assertThat(byUsernameInOrEmailIn.size()).isEqualTo(1);
assertThat(byUsernameInOrEmailIn.get(0).getEmail()).isEqualTo("[email protected]");
}
5. 結論
在本教程中,我們討論了 Spring Data 的查詢衍生功能,並使用它來尋找表中的實體。我們也探索了使用各種輸入參數來尋找具有 AND 和 OR 等條件的實體。
與往常一樣,範例程式碼可以在 GitHub 上取得。