순수 JPA와 Querydsl
• 순수 JPA 리퍼지토리와 Querydsl
• 동적쿼리 Builder 사용
• 동적쿼리 Where 사용
• 조회 API 컨트롤러 개발
1. 순수 JPA리퍼지토리와 Querydsl
순수 JPA를 사용한 리퍼지토리를 만들고, 테스트를 해본 뒤, Querydsl로 바꾸면서 둘을 비교해보자.
먼저 순수 JPA 리퍼지토리는 아래와 같다.
@Repository
public class MemberJpaReposiotory {
private final EntityManager em;
private final JPAQueryFactory queryFactory;
public MemberJpaReposiotory(EntityManager em) {
this.em = em;
this.queryFactory = new JPAQueryFactory(em);
}
public void save(Member member) {
em.persist(member);
}
public Optional<Member> findById(Long id) {
Member findMember = em.find(Member.class, id);
return Optional.ofNullable(findMember);
}
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class).getResultList();
}
public List<Member> findByUsername(String username) {
return em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", username)
.getResultList();
}
}
이를 테스트해보자.
@Transactional
@SpringBootTest
class MemberJpaReposiotoryTest {
@Autowired EntityManager em;
@Autowired MemberJpaReposiotory repository;
@Test
void save() {
repository.save(new Member("member1", 10));
}
@Test
void findById() {
Member member = new Member("member1", 10);
repository.save(member);
Member findMember = repository.findById(member.getId()).get();
Assertions.assertThat(member.getId()).isEqualTo(findMember.getId());
Assertions.assertThat(member.getUsername()).isEqualTo(findMember.getUsername());
Assertions.assertThat(member).isEqualTo(findMember);
}
@Test
void findAll() {
Member member1 = new Member("member1", 10);
Member member2 = new Member("member2", 10);
Member member3 = new Member("member3", 10);
repository.save(member1);
repository.save(member2);
repository.save(member3);
List<Member> result = repository.findAll();
Assertions.assertThat(result).contains(member1, member2, member3);
}
@Test
void findByUsername() {
Member member1 = new Member("member1", 10);
repository.save(member1);
List<Member> result = repository.findByUsername(member1.getUsername());
Member findMember = result.get(0);
Assertions.assertThat(findMember).isEqualTo(member1);
}
}
위의 테스트는 물론 성공한다.
순수 JPA 리퍼지토리의 findAll, findByUsername을 Querydsl을 사용하여 바꿔보자.
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class).getResultList();
}
/*Querydsl*/
public List<Member> findAll_Querydsl(){
return queryFactory.selectFrom(member).fetch();
}
public List<Member> findByUsername(String username) {
return em.createQuery("select m from Member m where m.username = :username", Member.class)
.setParameter("username", username)
.getResultList();
}
/*Querydsl*/
public List<Member> findByUsername_Querydsl(String username){
return queryFactory.selectFrom(member).where(member.username.eq(username)).fetch();
}
자바 코드를 사용하는 Querydsl이 훨씬 간편하고 가독성에도 좋은 것을 알 수 있다.
이제 이를 테스트해보자.
@Transactional
@SpringBootTest
class MemberJpaReposiotoryTest {
@Autowired EntityManager em;
@Autowired MemberJpaReposiotory repository;
@Test
void findAll() {
Member member1 = new Member("member1", 10);
Member member2 = new Member("member2", 10);
Member member3 = new Member("member3", 10);
repository.save(member1);
repository.save(member2);
repository.save(member3);
List<Member> result = repository.findAll();
Assertions.assertThat(result).contains(member1, member2, member3);
}
@Test
void findAll_Querydsl() {
Member member1 = new Member("member1", 10);
Member member2 = new Member("member2", 10);
Member member3 = new Member("member3", 10);
repository.save(member1);
repository.save(member2);
repository.save(member3);
List<Member> result = repository.findAll_Querydsl();
Assertions.assertThat(result).contains(member1, member2, member3);
}
@Test
void findByUsername() {
Member member1 = new Member("member1", 10);
repository.save(member1);
List<Member> result = repository.findByUsername(member1.getUsername());
Member findMember = result.get(0);
Assertions.assertThat(findMember).isEqualTo(member1);
}
@Test
void findByUsername_Querydsl() {
Member member1 = new Member("member1", 10);
repository.save(member1);
List<Member> result = repository.findByUsername_Querydsl(member1.getUsername());
Member findMember = result.get(0);
Assertions.assertThat(findMember).isEqualTo(member1);
}
}
해당 테스트도 물론 성공한다.
2. 동적쿼리 Builder 사용
동적쿼리Builder에 Dto조회를 적용하여 성능을 최적화해보자.
dto는 Member정보와 Team정보를 동시 조회할 것이다. 하여 MemberTeamDto를 만들고 compileQuerydsl을 하여 QMemberTeamDto를 만든다.
@Data
public class MemberTeamDto {
private Long memberId;
private String username;
private int age;
private Long teamId;
private String teamName;
@QueryProjection
public MemberTeamDto(Long memberId, String username, int age, Long teamId, String teamName) {
this.memberId = memberId;
this.username = username;
this.age = age;
this.teamId = teamId;
this.teamName = teamName;
}
}
그리고 동적쿼리의 Condition을 위한 MemberSearchCondition을 만든다.
@Data
public class MemberSearchCondition {
// 회원명, 팀명, 나이(ageGoe, ageLoe)
private String username;
private String teamName;
private Integer ageGoe;
private Integer ageLoe;
}
이제 리퍼지토리에 메서드를 만들어보자.
public List<MemberTeamDto> searchByBuilder(MemberSearchCondition condition) {
BooleanBuilder builder = new BooleanBuilder();
if (StringUtils.hasText(condition.getUsername()))
builder.and(member.username.eq(condition.getUsername()));
if (StringUtils.hasText(condition.getTeamName()))
builder.and(team.name.eq(condition.getTeamName()));
if (condition.getAgeGoe() != null)
builder.and(member.age.goe(condition.getAgeGoe()));
if (condition.getAgeLoe() != null)
builder.and(member.age.loe(condition.getAgeLoe()));
return queryFactory
.select(new QMemberTeamDto(
member.id,
member.username,
member.age,
team.id,
team.name
))
.from(member)
.leftJoin(member.team, team)
.where(builder) /* where 인자에 builder */
.fetch();
}
StringUtils.hasText메서드는 빈 문자열과 null을 확인해준다.
이제 이를 사용하는 테스트를 보자.
@Test
public void searchTest(){
Team teamA = new Team("teamA");
Team teamB = new Team("teamB");
em.persist(teamA);
em.persist(teamB);
Member member1 = new Member("member1", 10, teamA);
Member member2 = new Member("member2", 20, teamA);
Member member3 = new Member("member3", 10, teamB);
Member member4 = new Member("member4", 20, teamB);
Member member5 = new Member("member5", 55, teamB);
em.persist(member5);
em.persist(member1);
em.persist(member2);
em.persist(member3);
em.persist(member4);
// -- 컨티션 --//
MemberSearchCondition condition = new MemberSearchCondition();
condition.setAgeGoe(15);
condition.setAgeLoe(35); // -> 15~35살
condition.setTeamName("teamB"); // teamName은 teamB이어야 한다.
//username 컨디션은 추가하지 않음. 즉 username은 어찌되어도 상관없다는 것이다.
// -----------
List<MemberTeamDto> result = repository.searchByBuilder(condition);
assertThat(result.size()).isEqualTo(1);
assertThat(result.get(0).getUsername()).isEqualTo("member4");
}
해당 테스트는 성공한다.
다음 포스트에서
• 동적쿼리 Where 사용
• 조회 API 컨트롤러 개발
에 대해 알아보자.
김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.
'JPA > Querydsl' 카테고리의 다른 글
Querydsl 13 - 조회 API 컨트롤러 개발 (0) | 2022.01.22 |
---|---|
Querydsl 12 - 동적쿼리와 성능 최적화 조회(where 절 파라미터) (0) | 2022.01.22 |
Querydsl 10 - SQL function 호출하기 (0) | 2022.01.20 |
Querydsl 09 - 수정, 삭제 배치 쿼리 (0) | 2022.01.20 |
Querydsl 08 - 동적 쿼리 (0) | 2022.01.20 |