728x90
UserLoanHistoryRepository
interface UserLoanHistoryRepository : JpaRepository<UserLoanHistory, Long> {
fun findByBookName(bookName: String): UserLoanHistory?
fun findByBookNameAndStatus(bookName: String, status: UserLoanStatus): UserLoanHistory?
fun findByStatus(status: UserLoanStatus): List<UserLoanHistory>
fun countByStatus(status: UserLoanStatus): Long
}
- 해당 메서드들은 @Query를 사용한 것이 아닌 SpringDataJpa를 사용해서 만든 것이다
- 이는 리펙토링 해야 하나? -> 해야 된다(메서드 명도 짧아지고, 동적 쿼리의 편함이 있기때문)
- 만약 findBy 뒤에 오는 조건이 동적으로 온다면?
- 매번 새로운 메서드를 만들어야 한다(2^n으로 메서드가 많아진다)
- 메서드 명이 길어지고, 읽기 힘들다.
- where절에 들어오는 조건절이 동적으로 동작한다면 이를 QueryDsl을 사용하면 간단하게 작성할 수 있다.
UserLoanHistoryQuerydslRepository
@Component
class UserLoanHistoryQuerydslRepository(
private val queryFactory: JPAQueryFactory
) {
fun find(bookName: String, status: UserLoanStatus? = null): UserLoanHistory? {
return queryFactory.select(userLoanHistory)
.from(userLoanHistory)
.where(
userLoanHistory.bookName.eq(bookName),
status?.let { userLoanHistory.status.eq(status) }
)
.limit(1)
.fetchOne()
}
fun count(status: UserLoanStatus): Long {
return queryFactory.select(userLoanHistory.id.count())
.from(userLoanHistory)
.where(
userLoanHistory.status.eq(status)
).fetchOne() ?: 0L
}
}
- find()
- 파라미터로 받는 status 값은 null로 올 수 있기 때문에 null 허용 타입으로 설정한 뒤, 디폴트 파라미터로 null값을 주었다.
- where절에서 만약 status가 null이면 null값을 리턴하고 null이 아니면 let 함수를 실행한다.
- let함수에서 userHistory.status.eq(status) 쿼리를 실행해준다.
- where절에서 null 이면 and 절에 포함이 되지 않고, null이 아닌 값이 반환되면 해당 조건이 AND로 결합된다
- limit를 사용하여 SQL을 limit을 fetchOne을 사용해 하나의 데이터만 가지고 온다
- 함수명도 의미 있게 사용할 수 있다
- count
- count함수가 null을 반환할 수도 있으니 엘비스 연산자로 null을 반환하면 0을 반환하도록 한다.
BookService
@Service
class BookService(
private val bookRepository: BookRepository,
private val bookQuerydslRepository: BookQuerydslRepository,
private val userRepository: UserRepository,
private val userLoanHistoryRepository: UserLoanHistoryRepository,
private val userLoanHistoryQuerydslRepository: UserLoanHistoryQuerydslRepository, //새로 추가된 repository
) {
//...
@Transactional
fun loanBook(request: BookLoanRequest) {
//...
if (userLoanHistoryQuerydslRepository.find(
//...
}
//..
@Transactional(readOnly = true)
fun countLoanedBook(): Int {
return userLoanHistoryQuerydslRepository.count(UserLoanStatus.LOANED).toInt()
}
}
728x90
'실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기' 카테고리의 다른 글
| Ch04. 요구사항 추가(책 통계, QueryDSL) - QueryDSL 사용하기 (0) | 2022.11.08 |
|---|---|
| Ch04. 요구사항 추가(책 통계, QueryDSL) - QueryDSL 도입하기 (0) | 2022.11.08 |
| Ch04. 요구사항 추가(책 통계, QueryDSL) - 애플리케이션 대신 DB로 기능 구현 (0) | 2022.11.08 |
| Ch04. 요구사항 추가(책 통계, QueryDSL) - 책 통계 테스트 코드와 리펙토링 (0) | 2022.11.07 |
| Ch04. 요구사항 추가(책 통계, QueryDSL) - 책 통계 요구사항 추가 (0) | 2022.11.07 |