Spring Boot Data JPA Querydsl 적용하기

황세호·2021년 8월 7일
0

Spring Data

목록 보기
1/1

Spring Boot Data JPA Querydsl 적용


Spring Data JPA를 사용할 때, 기본으로 제공해주는 @Query로는 다양한 조회 기능을 사용하기에 한계가 있다.
그래서 이 문제를 해결하기 위해 정적 타입을 지원하는 조회 프레임워크를 사용하는데, 자주 사용되는 것이 Querydsl이다.

기본적으로, Querydsl을 사용하기 위해서는 Q클래스들이 생성되어 있어야 한다. 개발환경과 Gradle 설정과 같은 내용은 아래 참조 링크에서 확인할 수 있다. 필자는 Maven 방식으로 진행했다.

1. 기본 사용법


1-1. 기본적인 사용법

먼저 Entity하나를 생성한다.

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Academy {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private String address;

    @Builder
    public Academy(String name, String address) {
        this.name = name;
        this.address = address;
    }
}

그리고 테스트로 데이터를 넣고, 검증할 Repository도 하나 생성한다.

public interface AcademyRepository extends JpaRepository<Academy, Long> {
}

그럼 이제 Querydsl Repository를 하나 생성한다.
클래스명은 AcademyRepositorySupport이다.

@Repository
public class AcademyRepositorySupport extends QuerydslRepositorySupport {
    private final JPAQueryFactory queryFactory;

    public AcademyRepositorySupport(JPAQueryFactory queryFactory) {
        super(Academy.class);
        this.queryFactory = queryFactory;
    }

    public List<Academy> findByName(String name) {
        return queryFactory
                .selectFrom(academy)
                .where(academy.name.eq(name))
                .fetch();
    }

}

1-2. 기본 사용법 테스트

이제 테스트 코드를 통해 검증해보자.

@RunWith(SpringRunner.class)
@SpringBootTest
public class BasicTest {

    @Autowired
    private AcademyRepository academyRepository;

    @Autowired
    private AcademyRepositorySupport academyRepositorySupport;

    @After
    public void tearDown() throws Exception {
        academyRepository.deleteAllInBatch();
    }

    @Test
    public void querydsl_기본_기능_확인() {
        //given
        String name = "hsayho";
        String address = "hsayho@hsayho.com";
        academyRepository.save(new Academy(name, address));

        //when
        List<Academy> result = academyRepositorySupport.findByName(name);

        //then
        assertThat(result.size(), is(1));
        assertThat(result.get(0).getAddress(), is(address));
    }
}

2. Spring Data JPA Custom Repository 적용


위와 같은 방식에는 한 가지 단점이 있다.
항상 2개의 Repository를 의존성으로 받아야 한다는 것이다.

그 이유는 Querydsl의 Custom Repository와 JpaRepository를 상속한 Repository가 기능을 나눠가졌기 때문이다.

이를 해결하기 위해 Spring Data JPA에서는 Custom Repository를 JpaRepository 상속 클래스에서 사용할 수 있도록 기능을 지원한다.

전체적인 그림은 아래와 같다.

Spring Data JPA - Reference Documentation를 참고하면 Custom Repository에 대해 더 자세한 내용이 나오니 참고할 것!

Custom이 붙은 인터페이스를 상속한 Impl 클래스의 코드는 Custom 인터페이스를 상속한 JpaRepository에서 사용할 수 있다.

먼저 기존 Repository와 같은 위치에 Custom인터페이스와 Impl클래스를 생성한다.

그리고 WikiRepositoryCustom 인터페이스와 WikiRepositoryImpl 클래스에 다음과 같은 코드를 추가한다.

public interface WikiRepositoryCustom{
	List<String> findByName(String name);
}
@RequiredArgsConstructor
public class WikiRepositoryImpl implements WikiRepositoryCustom {

    private final JPAQueryFactory queryFactory;

    @Override
    public List<Wiki> findByName(String name) {
        return queryFactory.selectFrom(wiki)
                .where(wiki.name.eq(name))
                .fetch();
    }
}

여기서 페이징이 필요할 경우 QuerydslSupport 상속 코드를 추가하면 된다.

그럼 이제 이 코드를 WikiRepository에서 사용할 수 있게 상속 구조로 변경해보겠다.

public interface WikiRepository extends JpaRepository<Wiki, Long>, WikiRepositoryCustom {
}

그럼 정상적으로 작동하는지 테스트 코드를 작성해보자

@RunWith(SpringRunner.class)
@SpringBootTest
public class CustomTest {

    @Autowired
    private WikiRepository wikiRepository;

    @After
    public void tearDown() throws Exception {
        wikiRepository.deleteAllInBatch();
    }

    @Test
    public void querydsl_Custom설정_기능_확인() {
        //given
        String name = "hsayho";
        String address = "hsayho@hsayho.com";
        wikiRepository.save(new Wiki(name, address));

        //when
        List<Wiki> result = wikiRepository.findByName(name);

        //then
        assertThat(result.size(), is(1));
        assertThat(result.get(0).getAddress(), is(address));
    }
}

이 외에도 따로 상속/구현 없이 따로 Repository를 생성하여 JPAQueryFactory를 사용해 Querydsl을 사용하는 방법이 있다.

1번의 경우 @DataJpaTest 방법


1번 방법을 사용할 경우, DataJpaTest로 작성할 경우에 queryFactory 및 상속용 클래스들이 빈으로 등록되지 않는 문제가 발생한다.

이럴 경우에는

@TestConfiguration
    static class TestConfig {

        @PersistenceContext
        private EntityManager entityManager;

        @Bean
        public JPAQueryFactory jpaQueryFactory() {
            return new JPAQueryFactory(entityManager);
        }
    }

위와 같은 TestConfig 파일을 test 전용 configuration 폴더에 옮긴 후에, @DataJpaTest를 사용하는 곳에서 해당 클래스를 Import하는 방식으로 jpaQueryFactory의 의존성 주입을 해결할 수 있다.

REFERENCE


출처 : Spring Boot Data Jpa 프로젝트에 Querydsl 적용하기

profile
Developer

0개의 댓글