1. where 절 검색 조건 쿼리
where 절에 JPQL에서 제공하는 문법을 모두 제공한다 . (= , >= ,<= ,>, < , like , between 등등 . . )
@Test
void search(){
Member findMember = qf
.selectFrom(member)
.where(
// and 사용하지 않고 , 으로도 표현 가능
member.username.eq("member1")
,member.age.eq(10)
,member.username.startsWith("mem")
,member.id.in(1L,2L,3L))
.fetchOne();
assertEquals(findMember.getUsername(),"member1");
assertEquals(findMember.getAge(),10);
}
where의 파라미터는 ... 문법 으로 여러개를 받기 때문에 위의 코드처럼 and로 조건을 사용하지 않고 쉼표 , 로 구분해줘도 동작한다.
2. 결과 조회
결과 조회를 하는 메서드는 아래와같다
@Test
void resultTest(){
//.fetchOne() 단건조회
Member member = qf
.selectFrom(QMember.member)
.where(
QMember.member.username.eq("member1"))
.fetchOne();
//.fetchFirst() limit(1).fetchOne과 같음;
Member fetchFirst = qf
.selectFrom(QMember.member)
.where(
QMember.member.username.eq("member1"))
.fetchFirst();
//.fetchResults() 페이징 정보 포함
QueryResults<Member> fetchResults = qf
.selectFrom(QMember.member)
.where(
QMember.member.username.eq("member1"))
.fetchResults();
long limit = fetchResults.getLimit();
long offset = fetchResults.getOffset();
List<Member> results = fetchResults.getResults();
long total = fetchResults.getTotal();
//fetchCount(); 카운트 쿼리만 나감
long fetchCount = qf
.selectFrom(QMember.member)
.where(
QMember.member.username.eq("member1"))
.fetchCount();
}
//.fetch() 리스트 조회
//.fetchFirst() limit(1).fetchOne과 같음;
//.fetchResults() 페이징 정보 포함 , total count 쿼리 추가로 실행
//.fetchCount() count쿼리 조회
fetchResult의 경우 페이징 쿼리가 복잡해 질때 컨텐츠를 가져오는 쿼리와 실제 total 카운트를 가져오는 쿼리를 성능 최적화를 위해 변경해야 할 수도 있다. 그럴 경우에는 fetchResult 를 사용 하는 것 보다는 query를 튜닝하여 직접 쿼리를 따로 날리는 것이 좋다 .
3.정렬
@Test
void sort(){
em.persist(new Member(null,100));
em.persist(new Member("member5",100));
em.persist(new Member("member6",100));
List<Member> result= qf.selectFrom(member)
.where(member.age.eq(100))
.orderBy(member.username.asc().nullsLast(), member.age.desc())
.fetch();
Member member5 = result.get(0);
Member member6 = result.get(1);
Member memberNull = result.get(2);
assertEquals(member5.getUsername(),"member5");
assertEquals(member6.getUsername(),"member6");
assertEquals(memberNull.getUsername(),null);
}
orderBy() 메서드로 정렬조건을 추가해 줄 수 있다 , asc , desc , nullsLast(Null이면 마지막으로 정렬 ), nullFirst(Null이면 마지막으로 정렬) 등으로 정렬 해줄 수 있고 , where 절과 마찬 가지고 여러개의 조건을 , 으로 구분하여 넣어 줄 수 있다.
4.페이징
@Test
void paging1(){
List<Member> result= qf.selectFrom(member)
.where(member.username.like("member%"))
.orderBy(member.username.asc())
.offset(0)
.limit(2)
.fetch();
assertEquals(result.size() , 2);
}
@Test
void paging2(){
QueryResults<Member> results = qf.selectFrom(member)
.where(member.username.like("member%"))
.orderBy(member.username.asc())
.offset(0)
.limit(2)
.fetchResults();
assertEquals(results.getResults().size() , 2);
assertEquals(results.getTotal(), 4);
}
paging 1의 경우 offset과 limit를 줘서 컨탠츠 갯수만 제한을 줘서 가져오는 것이고
paging 2는 fetchResults로 받아 페이징 정보(totalCount , result,limit,offsett)를 포함해서 가져온다 .
paging 2의 경우에는 총 갯수를 구하는 쿼리와 , 엔티티 리스트를 조회하는 쿼리 두방이 나가는데
이전에 말했던 것처럼 해당 쿼리에 대해서 튜닝이 필요한 경우에는 fetchResults보다는 각각 쿼리를 튜닝하여 따로 날리는게 더 좋다 .
4.집합
@Test
void aggregation(){
List<Tuple> result = qf
.select(
member.count(),
member.age.sum(),
member.age.avg(),
member.age.max(),
member.age.min())
.from(member)
.fetch();
//List내에 Tuple은 타입이 여러개일 때 사용한다 .
//아래의 튜플은 queryDsl의 튜플이다
Tuple tuple = result.get(0);
Long count = tuple.get(member.count());
assertEquals(count,4);
assertEquals(tuple.get(member.age.sum()),46);
assertEquals(tuple.get(member.age.avg()), (46/4f));
}
@Test
void group(){
//given
List<Tuple> fetch = qf.select(team.name, member.age.avg())
.from(member)
.join(member.team, team)
.groupBy(team.name)
.fetch();
Tuple teamA = fetch.get(0);
Tuple teamB = fetch.get(1);
assertEquals(teamA.get(team.name),"teamA");
assertEquals(teamA.get(member.age.avg()),10.5f);
}
aggregation 테스트를 보면 함수를 활용하여 멤버의 합 , 평균 , 최대값,최소값을 조회하고 있다.
이 경우 반환 타입이 Tuple로 나오는데 Tuple은 결과값이 여러가지 타입을 가졌을때 반환되는 타입이고 위의 Tuple은 queryDsl의 Tuple이다 . queryDsl 에서 tuple 객체에 담긴 값은 위의 tuple.get(member.count()) 같이 조회 때 사용한 필드명으로 빼서 쓸 수 있다 .
gropBy도 사용할 수 있다 . .groupBy()로 그룹할 조건을 지정해 주면되고 Having()도 사용 가능하다 .
위의 경우 team이 같은 멤버를 그룹으로 하고 그 그룹의 나이의 평균값을 구하는 코드이다
위 처럼 select절에서 엔티티가 아닌 값 타입으로 조회할 때는 위처럼 각각의 컬럼명을 지정해서 tuple로 받아서 쓰는 것보다는
Dto를 만들어서 조회하는 것이 좋다 .
'JPA > QueryDSL' 카테고리의 다른 글
QueryDSL 공부 5 - 프로젝션과 결과 반환 (0) | 2021.06.19 |
---|---|
QueryDSL 공부 4 - QueryDSL 활용2 (join문) (0) | 2021.06.19 |
QueryDSL 공부 2 - Q-Type 활용 (0) | 2021.06.18 |
QueryDSL 공부 1 - queryDSL 설정 (0) | 2021.06.18 |
Spring boot -QueryDSL 과 JPQL 차이점 (0) | 2020.11.27 |