querydsl

JPA와 querydsl

querydsl 시작하기

EntityManager와 JPAQueryFactory를 주입/생성한다.

 private final EntityManager em;
 private final JPAQueryFactory queryFactory;

 public MemberJpaRepository(EntityManager em) {
   this.em = em;
   this.queryFactory = new JPAQueryFactory(em);
 }

 @Bean
JPAQueryFactory jpaQueryFactory(EntityManager em) {
    return new JPAQueryFactory(em);
}

위처럼 직접 Constructor를 작성해도 좋고, 아래처럼 스프링 컨테이너가 주입하도록 설정해도 된다.

추가

스프링이 주입하는 엔티티 매니저는 실제 동작 시점에 진짜 엔티티 매니저를 찾아주는 프록시용 가짜 엔티티 매니저이다. 이 가짜 엔티티 매니저는 실제 사용 시점에 트랜잭션 단위로 실제 엔티티 매니저(영속성 컨텍스트)를 할당해준다.

null 체크에 유용한 static method

import org.springframework.util.StringUtils.*;

hasText() // notBlank()
isEmpty() // 지금은 deprecated로 ObjectUtils.isEmpty를 선호

Spring Data JPA과 querydsl 함께 쓰기

자동으로 메서드이름에 맞는 JPQL을 생성하는 spring data jpa에 구현 코드를 필요로 하는 querydsl을 쓰기 위해서는 사용자 정의 리포지토리를 필요로 한다.

Step 1

사용자 정의 인터페이스를 생성한다.

public interface MemberRepositoryCustom {
     List<MemberTeamDto> search(MemberSearchCondition condition);
}

Step 2

사용자 정의 인터페이스의 구현체를 작성한다.
나는 이 부분에서 "그럼 왜 인터페이스를 작성하지? 그냥 구현체만 짜도 될거 같은데?"라고 생각했다.
이유는 레포지토리의 다형성을 이용하기 위해 spring data jpa 레포지토리 인터페이스에 사용자 정의 인터페이스를 확장한다면 persistence layer에서 주입받던 레포지토리를 그대로 사용할 수 있기 때문이다.

public class MemberRepositoryImpl implements MemberRepositoryCustom {

     private final JPAQueryFactory queryFactory;

     public MemberRepositoryImpl(EntityManager em) {
         this.queryFactory = new JPAQueryFactory(em);
     }

   @Override
   //회원명, 팀명, 나이(ageGoe, ageLoe)
   public List<MemberTeamDto> search(MemberSearchCondition condition) {
     return queryFactory
       .select(new QMemberTeamDto(
           member.id,
           member.username,
           member.age,
           team.id,
           team.name))
       .from(member)
       .leftJoin(member.team, team)
       .where(usernameEq(condition.getUsername()),
           teamNameEq(condition.getTeamName()),
           ageGoe(condition.getAgeGoe()),
           ageLoe(condition.getAgeLoe()))
       .fetch();
   }

   private BooleanExpression usernameEq(String username) {
           return isEmpty(username) ? null : member.username.eq(username);
   }

   private BooleanExpression teamNameEq(String teamName) {
           return isEmpty(teamName) ? null : team.name.eq(teamName);
   }

   private BooleanExpression ageGoe(Integer ageGoe) {
           return ageGoe == null ? null : member.age.goe(ageGoe);
   }

   private BooleanExpression ageLoe(Integer ageLoe) {
           return ageLoe == null ? null : member.age.loe(ageLoe);
   }
}

위 예시에서 구현한 클래스의 이름이 MemberRepositoryImpl인 것처럼 spring data jpa repository 이름에 Impl을 붙여서 만들어야만 한다.

'스프링' 카테고리의 다른 글

[Spring Security] HTTP Basic Authentication를 사용한 간단한 인증 처리  (0) 2024.03.26
QueryDSL 비벼먹기  (0) 2023.10.24
QueryDSL 볶아먹기  (0) 2023.10.22
QueryDSL 다져먹기  (0) 2023.10.21
QueryDSL 먹어버리기  (0) 2023.10.20