-
JPA Specification를 사용하여 조인,검색기능 만들기JPA 2023. 12. 25. 15:21반응형
이 포스트는 Specification의 사용법만 설명한다. 기타 페이징 적용, response방법 등은 생략한다
JPA Specification란?
1. JPA Specification은 Java Persistence API (JPA)에서 제공하는 기능 중 하나로, 동적으로 쿼리를 생성하는 방법을 제공
2. JPA는 자바 어플리케이션에서 관계형 데이터베이스와 상호 작용할 수 있게 해주는 API
3. JpaRepository 상속받을때 JpaSpecificationExecutor도 같이 속받으면 된다.
테스트를 진행하려면 아래의 파일들이 필요하다.
AccountSpecification.java
public class AccountSpecification { //거래처명 검색 public static Specification<Account> likeAccountName(String accountName) { return new Specification<Account>() { private static final long serialVersionUID = 1L; @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) { // 2) like return criteriaBuilder.like(root.get("accountName"), "%" + accountName + "%"); } }; } //본인 부서 public static Specification<Account> equalDepartmentCode(Integer departmentCode) { return (Specification<Account>) (root, query, builder) -> { if (departmentCode == null) { return null; } Join<Account, Employee> empJoin = root.join("employee", JoinType.INNER); //사원테이블과 조인 (emplyCode) 기준 Join<Employee, Department> deptJoin = empJoin.join("department", JoinType.INNER); // 부서테이블과 조인 (departmentCode 기준) return builder.equal(deptJoin.get("departmentCode"), departmentCode); // 부서 코드 일치 조건 }; } }
거래처테이블 Account.java (Entity)
@Entity @Table(name = "tb_account") @NoArgsConstructor(access = PROTECTED) @Getter @EntityListeners(AuditingEntityListener.class) public class Account { @Id @GeneratedValue(strategy = IDENTITY) private Long accountCode; //거래처코드 @Column(nullable = false) private String accountNumber; //거래처연락처 @Column(nullable = false) private String accountName; //거래처명 @JoinColumn(name = "emplyCode") //직원테이블 관계 설정 private Employee employee; }
사원(회원)테이블 Employee.java(Entity)
@Entity @Table(name = "tb_employee") @Getter @NoArgsConstructor(access = PROTECTED) @EntityListeners(AuditingEntityListener.class) public class Employee { @Id @GeneratedValue(strategy = IDENTITY) private Long emplyCode; //사원코드 private String emplyName; //사원이름 @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "departmentCode") private Department department; //부서코드 }
부서 테이블 Department.java(Entity)
@Entity @NoArgsConstructor(access = PROTECTED) @Getter @Table(name = "tb_department") public class Department { @Id @GeneratedValue(strategy = IDENTITY) private Long departmentCode; //부서코드 @Column(nullable = false) private String departmentName; //부서이름 }
<!-- 내용 검색 콤보박스 --> <slect id="schType" name="schType"> <option value="">전체</option> <option value="accountName">거래처명</option> <option value="accountNumber">거래처번호</option> </slect> <!-- 검색어 키워드 --> <input type="text" name="schText" id="schText" placeholder="검색어를 입력하세요."> <!-- 부서 검색 콤보박스 --> <slect id="departmentCode" name="departmentCode"> <option value="">전체</option> <option value="1">영업부</option> <option value="2">개발부</option> </slect>
AccountService.java
@Transactional(readOnly = true) public Page<AccountListResponse> getFindAll(final Integer page, Integer departmentCode, String schType, String schText) { Specification<Account> spec = (root, query, criteriaBuilder) -> null; //1. 검색타입이 거래처명일때 if ("accountName".equals(schType)) { spec = spec.and(AccountSpecification.likeAccountName(schText)); } //2. 부서코드가 0이면 전체, 0이 아니면 선택한 부서코드로 조회 if(departmentCode != 0) { spec = spec.and(AccountSpecification.equalDepartmentCode(departmentCode)); } Page<Account> accountList = accountRepository.findAll(spec, getPageable(page)); return accountList.map(account -> AccountListResponse.from(account)); }
※ 서비스 자바 내용중 if의 조건이 충족하면 spec에 and키워드로 조건이 누적이 된다.
-- 검색조건테스트
1. 거래처명을 '테슬라' 라는 키워드로 검색하기 (테이블에 있는 컬럼)
-- SQL 결과
select account0_.account_code as account_1_0_, account0_.account_name as account_4_0_, account0_.account_number as account_5_0_ from tb_account account0_ where account0_.account_name like '%테슬라%' order by account0_.account_code desc limit 10
2. 거래처명을 '테슬라' 라는 키워드로 검색하고 부서코드 1로 조회하기(조인 후 다른 테이블의 컬럼검색)
select account0_.account_code as account_1_0_, account0_.account_name as account_4_0_, account0_.account_number as account_5_0_ from tb_account account0_ inner join tb_employee employee1_ on account0_.emply_code=employee1_.emply_code inner join tbl_department department2_ on employee1_.department_code=department2_.department_code where department2_.department_code=1 and ( account0_.account_name like '%테슬라%' ) order by account0_.account_code desc limit 10
거래처명을 테슬라로 검색하고 부서코드를 1로 조회했다.
AccountService.java에서 if문의 조건이 전부 성립하여 spec에 쿼리가 누적되어 SQL이 완성되었다.
반응형'JPA' 카테고리의 다른 글