직장 동료의 조언 덕분에 Querydsl 설정 방법에도 여러가지가 있다는 것을 알았습니다.
지난번에 작성한 Spring Data JPA 기반 Querydsl 사용해보자. ( Entity 관계 매핑 편, 테스트 코드 포함 )글에서는 QuerydslRepositorySupport를 상속받아 사용하는 방법에 대해서 작성하였습니다.
이번글에서는 이 것외에도 2가지가 더 있고 어떤 것을 선택했는지까지 작성하겠습니다.
모든 소스는 Github에 있습니다.
이동욱님의 티스토리를 참조해서 작성하였습니다. (https://jojoldu.tistory.com/372)
Querydsl 사용방법 3가지
- QuerydslRepositorySupport 상속받아 사용
- JpaRepistory에서 Querldsl 사용 가능하도록 설정하여 사용
- 상속 구현없이 Querydsl만 사용
1. QuerydslRepositorySupport 상속받아 사용
현재 진행중인 프로젝트에서 기존에 썼던 방식입니다.
@Repository
public class StoreRepositorySupport extends QuerydslRepositorySupport {
private final JPAQueryFactory jpaQueryFactory;
/**
* Creates a new {@link QuerydslRepositorySupport} instance for the given domain type.
*
* @param domainClass must not be {@literal null}.
*/
public StoreRepositorySupport(JPAQueryFactory jpaQueryFactory) {
super(Store.class);
this.jpaQueryFactory = jpaQueryFactory;
}
public Store findOneByName(String name) {
return jpaQueryFactory
.selectFrom(store)
.where(store.name.eq(name))
.fetchOne();
}
public List<StaffVo> findStaffsByName(String name) {
return jpaQueryFactory
.select(Projections.fields(StaffVo.class,
staff.id
, staff.age
, staff.name
))
.from(store)
.join(store.staff, staff) // 1)
.where(store.name.eq(name))
.fetch();
}
}
소스에서 QuerydslRepositorySupport 를 상속받아 사용할 수 있습니다. 생성자에서 super(domain.class); 를 설정하고 JPAQueryFactory를 사용합니다.
public interface StoreRepository extends JpaRepository<Store, Long> {
Store findByName(String name);
}
jpa로 작성가능한 간단한 쿼리는 StoreRepository를 사용
inner join 등 복잡성이 높은 쿼리는 StoreRepositorySupper 를 사용
Service에서 의존성을 2개 선언해야합니다.
장점이라고 생각하면 명확하게 2개로 분리되있기 때문에 좋다!
단점이라고 생각하면 Service에 의존성이 불필요하게 두개씩 생긴다!
2. JpaRepistory에서 Querldsl 사용 가능하도록 설정하여 사용
이 방법으로 최종 결정되어 적용하였습니다.
총 3가지 파일을 생성합니다.
StaffRepository
JpaRepository, CustomizedStaffRepository을 상속받습니다.
Service에서 의존성 주입하여 사용할 interface입니다.
public interface StaffRepository extends JpaRepository<Staff, Long>, CustomizedStaffRepository {
}
CustomizedStaffRepository
StaffRepository에 상속시킬 interface입니다.
StaffRepository에서 CustomizedStaffRepositoryImpl에서 작성된 로직을 실행할 수 있게 하는 interface입니다.
public interface CustomizedStaffRepository {
List<Staff> searchAll();
StaffVo search(Long id);
Staff findStaffById(Long id);
}
CustomizedStaffRepositoryImpl
CustomizedStaffRepository를 implements하여 Querydsl을 구현할 class입니다.
import static com.example.querydsl.staff.entity.QStaff.staff;
@RequiredArgsConstructor // 의존성 주입
public class CustomizedStaffRepositoryImpl implements CustomizedStaffRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<Staff> searchAll() {
return jpaQueryFactory
.selectFrom(staff)
.fetch();
}
@Override
public StaffVo search(Long id) {
return jpaQueryFactory
.select(Projections.fields(StaffVo.class,
staff.id,
staff.name
))
.from(staff)
.where(staff.id.eq(id))
.fetchOne();
}
@Override
public Staff findStaffById(Long id) {
return jpaQueryFactory
.selectFrom(staff)
.where(staff.id.eq(id))
.fetchOne();
}
}
Test 코드를 작성해서 테스트하면 모두 성공으로 결과값이 나옵니다.
@ActiveProfiles("local")
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class StaffRepositoryTest {
@Autowired
private StaffRepository staffRepository;
@Test
void searchAll() {
//given
//when
List<Staff> staff = staffRepository.searchAll();
//then
assertThat(staff).isNotNull();
}
@Test
void search() {
//given
final Long id = 1L;
//when
StaffVo search = staffRepository.search(id);
//then
assertThat(search.getId()).isEqualTo(id);
}
@Test
@Transactional
@Rollback(value = false)
void find_후_저장테스트() { // querydsl로 Entity를 조회하고 값을 변경하고 transaction이 끝나면 변경 컬럼이 Update된다.
//given
final Long id = 1L;
final String name = "임임용태";
Staff staff = staffRepository.findStaffById(id);
//when
staff.changeName(name);
//then
}
}
Service에서 의존성을 1개만 주입해서 JPA, Querydsl 모두 쓸 수 있습니다.
Service 의존성 리스트가 훨씬 줄어들겠네요!
3. 상속, 구현없이 Querydsl만 사용
조졸도님이 선호하는 방법이라고 합니다. :) ( 티스토리 참조 )
이 방법은 테스트해보지 않았습니다. JpaRepository에서 쉽게 호출가능한 쿼리들도 모두 구현해야할 것 같아서 제외하고 생각하였습니다.
구현 방법은 글 초입부에 링크를 걸어두었습니다. 참조해주세요 :)
결론
어떤 방법이 좋다! 는 없습니다.
개발은 개인, 팀의 취향이라고 생각합니다. 개인이라면 취향에 맞게 사용하시면 되고, 팀이라면 팀원들과 충분한 커뮤니케이션 후 결정하시면 될 것 같습니다 :)
p.s Spring에서 아직 Querydsl을 적극적으로 지원해준다는 생각은 들지 않네요.. ㅠ
'Develop > spring-data' 카테고리의 다른 글
[Querydsl] Querydsl을 적용하며.. class 파일명 주의 (1) | 2020.12.18 |
---|---|
[JPA] Querydsl에 pageable을 적용하며... 2가지 방법을 소개하겠습니다. (2) | 2020.12.10 |
[JPA] JPA를 적용하며... mysql 함수 2번 호출되는 문제 (0) | 2020.12.06 |
[JPA] JPA를 적용하며.. ( field convert 편 ) (1) | 2020.11.30 |
[JPA] JPA를 적용하며.. ( insert, update 분기 편 ) (1) | 2020.11.27 |