2020. 9. 4. 18:59ㆍ개발/DBMS
[3주차]
중급문법 ( JOIN, DTO 조회, 동적쿼리)
1. JOIN
-
조인 문법을 사용하여 연관 관계가 있는 ENTITY 혹은 연관 관계가 없는 ENTITY 간 조인이 가능하다
1-1. 연관 관계가 있는 ENTITY
List<Member> result = queryFactory
.selectFrom(member)
.join(member.team, team)
.where(team.name.eq("teamA"))
.fetch();
1-2. 연관 관계가 없는 ENTITY
List<Member> result = queryFactory
.selectFrom(member)
.from(member, team)
.where(member.username.eq(team.name))
.fetch();
JOIN 문법
문법 | 기능 |
join(), innerJoin() |
내부 조인 |
leftJoin() |
left 외부 조인 |
rightJoin() |
right 외부 조인 |
fetchJoin() |
성능 최적화 (N +1 문제 해결 방법 중 한개) |
2. SUBQUERY
-
com.querydsl.jpa.JPAExpressions 를 사용 하여 subQuery가 가능하다.
-
단, 해당 기능에는 단점 도 존재한다. 그것 은 바로 subQuery를 쓸 수 있는 곳이 한정 적이다.
-
가능한 곳: select, where 절
-
불가능한 곳: from 절
-
-
subquery 가 안되는 곳에서의 대처법
-
서브쿼리를 JOIN으로 변경한다
-
쿼리를 분리해서 실행한다
-
nativeSQL를 사용한다(비추)
-
2-1. where 절의 subQuery
Member findMember = queryFactory
.selectFrom(member)
.where(member.age.eq(
JPAExpressions.select(memberSub.age.max()).from(memberSub)
))
.fetchOne();
2-2. select 절의 subQuery
QMember memberSub = new QMember("memberSub");
List<Tuple> result = queryFactory
.select(member.username,
JPAExpressions.select(memberSub.age.avg()).from(memberSub))
.from(member)
.fetch();
3. CASE 문
-
.when().then().otherwise() 사용 하여 간단히 case 문 작성 가능
List<String> result = queryFactory
.select(new CaseBuilder()
.when(member.age.between(0, 20)).then("0 ~ 20살")
.when(member.age.between(21, 30)).then("21 ~ 30살")
.otherwise("기타"))
.from(member)
.fetch();
CASE 문법
문법 | 기능 |
.when() |
조건 |
.then() |
.when()의 조건을 만족했을때 나오는 값 |
.otherwise() |
.조건에 만족하는 값 외 것은 나타는 값 |
4. DTO 조희
-
ENTITY의 값을 그대로 가져오지 않고 중간 객체를 지정하여 가져 올 수도 있다.
-
DTO 조회 방법
4-1. JPQL 를 사용 한 경우
List<MemberDto> result = em.createQuery(
"select new me.study.querydslsample.dto.MemberDto(m.username, m.age) " +
"from Member m", MemberDto.class)
.getResultList();
4-2. 프로퍼티(setter) 사용 한 경우
List<MemberDto> result = queryFactory
.select(Projections.bean(MemberDto.class,
member.username, member.age))
.from(member)
.fetch();
4-3. 필드를 사용 한 경우
List<MemberDto> result = queryFactory
.select(Projections.fields(MemberDto.class,
member.username, member.age))
.from(member)
.fetch();
4-4. 생성자를 사용 한 경우
List<MemberDto> result = queryFactory
.select(Projections.constructor(MemberDto.class,
member.username, member.age))
.from(member)
.fetch();
4-5. QueryProjection 를 사용 한 경우
-
사전 준비 가져올 DTO에 어노테이션 기반의 생성자를 만들어 줘야한다.
@QueryProjection를 사용 하여 생성자 생성
import com.querydsl.core.annotations.QueryProjection;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class MemberDto {
private String username;
private int age;
@QueryProjection
public MemberDto(String username, int age) {
this.username = username;
this.age = age;
}
}
실 사용
List<MemberDto> result = queryFactory
.select(new QMemberDto(member.username, member.age))
.from(member)
.fetch();
DTO 를가져오는 다양한 방법
문법 | 기능 | 특징 |
Projections.bean(클래스,컬럼) |
프로퍼티(setter) 사용 |
|
Projections.fields(클래스,컬럼) |
필드를 사용 |
|
Projections.constructor(클래스,컬럼) |
생성자 사용 |
|
new QClassName(컬럼) |
QueryProjection 사용 |
장점
단점
|
5. 동적 쿼리
-
querydsl 를 사용하면 복잡한 동적 쿼리를 매우 간편하게 작성 가능하다. 개인적으로 querydsl 의 가장 큰 장점으로 생각한다.
5-1. BooleanBuilder 를 사용하는 방법
-
자바 코드 짜듯이 간편하게 사용할 수있다.
private List<Member> searchMember(String username, Integer age) {
BooleanBuilder builder = new BooleanBuilder();
if (username != null) {
builder.and(member.username.eq(username));
}
if (age != null) {
builder.and(member.age.eq(age));
}
return queryFactory
.selectFrom(member)
.where(builder).fetch();
}
5-2. BooleanExpression 를 사용하는 방법
-
해당 부분은 5-1 보다 더 자바 코드 처럼 짤 수있는 방법으로 각 조건을 메소드화 하여 사용 하는 방법이다. (이 방법을 추천한다)
-
이 방법으로 사용하면 핵심 비지니스 로직을 확인하는데 용이하다.
private List<Member> searchMember(String username, Integer age) {
return queryFactory
.selectFrom(member)
.where(usernameEq(username), ageEq(age))
.fetch();
}
private BooleanExpression ageEq(Integer age) {
return age != null ? member.age.eq(age) : null;
}
private BooleanExpression usernameEq(String username) {
return username != null ? member.username.eq(username) : null;
}
private BooleanExpression allEq(String username, Integer age) {
return usernameEq(username).and(ageEq(age));
}
[3주차]-END
참고: www.inflearn.com/course/Querydslwww.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84
실전! Querydsl - 인프런
Querydsl의 기초부터 실무 활용까지 한번에 해결 중급이상 웹 개발 데이터베이스 서버 개발 Back-End Java JPA Spring Data JPA JQuery 온라인 강의 쿼리, JSP, 실전 Querydsl, 김영한 강의, jpa 강의
www.inflearn.com
'개발 > DBMS' 카테고리의 다른 글
[Querydsl] querydsl 학습_4 (0) | 2020.11.23 |
---|---|
[Querydsl] querydsl 학습_2 (0) | 2020.08.28 |
[Querydsl] querydsl 학습_1 (0) | 2020.08.19 |
[Querydsl] querydsl 적용시 주의점 (1) | 2019.11.08 |