ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Querydsl (3) - 순수 JPA와 Querydsl
    Web/QueryDSL 2024. 1. 24. 15:22

     

     

    - 순수 JPA 리포지토리와 Querydsl은 같은 Repository에 손쉽게 사용 가능하다.

     

    @Repository
    public class MemberJpaRepository {
     private final EntityManager em;
     private final JPAQueryFactory queryFactory;
     public MemberJpaRepository(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();
     }
    }

     

    ** JAPQueryFactory는 위와 같이 생성자에서 주입 받는 방식을 고려해 봅시다.

    그런게 아니라면 빈으로 등록 

     

    public List<Member> findAll_Querydsl() {
     return queryFactory
     .selectFrom(member).fetch();
     }
     
     public List<Member> findByUsername_Querydsl(String username) {
     return queryFactory
     .selectFrom(member)
     .where(member.username.eq(username))
     .fetch();
     }

     

    2. 동적 쿼리 Builder 사용하기 

     

    @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;
     }
    }
    
    
    @Data
    public class MemberSearchCondition {
     //회원명, 팀명, 나이(ageGoe, ageLoe)
     private String username;
     private String teamName;
     private Integer ageGoe;
     private Integer ageLoe;
    }

     

    - @QueryProjection으로 DTO도 Q타입으로 추가 

    - 검색조건 담을 클래스 추가 

     

    BooleanBuilder builder = new BooleanBuilder();
     if (hasText(condition.getUsername())) {
     builder.and(member.username.eq(condition.getUsername()));
     }
     if (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)
     .fetch();

     

    - 빌더사용 

    - hasText부분은 Spring에서 제공하는 StringUtils를 사용한 것이다.

    - 빌더는 and나 or 등으로 where 문에 들어갈 조건을 연결 할 수 있다.

     

    *Q타입이 생성이 안되면, 임의로 임포트 해줘도 됨!

     

    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);
    }

     

    - Where에 ,를 구분하여 조건을 추가

    - 각 메서드의 리턴 타입은 BooleanExpression으로 해야 .and.or로 조건을 연결할 수 있다. 

    - 또한 한번 만들어둔 메서드는 재사용이 가능하다! 

     

     

    * 테스트 팁

     

    //.yml파일
    spring:
     	profiles:
     		active: local
     
     spring:
     	profiles:
    	 active: test
         
     //프로 파일 구분 가능 
    @Profile("local")
    @Component
    @RequiredArgsConstructor
    public class InitMember
    
    //특정 프로파일에서만 작동하는 빈을 생성할 수 있다.!
    // 주로 개발서버는 dev, 운영은 real이런식으로 active를 준다.

     

    'Web > QueryDSL' 카테고리의 다른 글

    Querydsl (4) - 스프링 데이터 JPA + Querydsl  (0) 2024.01.24
    Querydsl (1) - 기본 문법  (0) 2024.01.24
Designed by Tistory.