-
Querydsl (3) - 순수 JPA와 QuerydslWeb/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