개발놀이터
Querydsl 중급문법 본문
*프로젝션과 결과 반환
프로젝션 : select 대상 지정
-프로젝션 대상이 하나일 때 (단일 타입)
List<String> result = queryFactory.select(member.username).from(member).fetch();
1. 프로젝션 대상이 하나면 타입을 명확하게 지정할 수 있음
2. 프로젝션 대상이 둘 이상이면 튜플이나 DTO로 조회
-프로젝션 대상이 둘 이상일 때 (튜플 사용)
List<Tuple> result = queryFactory.select(member.username, member.age).from(member).fetch();
-사용방법
for (Tuple tuple : result) {
String username = tuple.get(member.username);
Integer age = tuple.get(member.age);
}
튜플을 사용할 때는 repository레벨에서만 사용하고 service, controller레벨에선 사용하지 않는 것이 좋다.
-프로젝션 대상이 둘 이상일 때 (DTO 조회)
1. 프로퍼티접근 (Setter 이용)
queryFactory
.select(Projection.bean(MemberDto.class, member.username, member.age))
.from(member)
.fetch();
2. 필드접근
queryFactory
.select(Projection.fields(MemberDto.class, member.username, member.age))
.from(member)
.fetch();
3. 생성자사용
queryFactory
.select(Projection.constructor(MemberDto.class, member.username, member.age))
.from(member)
.fetch();
cf)QueryProjection 사용
DTO의 생성자 부분에 @QueryProjection을 달아주고 compileQuerydsl을 실행 하면 Q타입의 DTO가 생긴다. 이후에
queryFactory.select(new QMemberDto(member.username, member.age)).from(member).fetch();
이렇게 사용하면 된다.
QueryProjection의 장단점
장점 : 생성자를 생성할 때 DTO에서의 데이터들을 가지고 생성하는 것이기 때문에 실수로 더 많이 혹은 더 적게 인자값을 넘겨주면 컴파일단계에서 오류가 발생한다. 그러므로 굉장히 안전한 방법이다.
단점 : DTO가 QueryDSL에 의존성을 가지고 종속적으로 바뀐다. 또한 DTO를 Q타입으로 또 하나 생성해야 한다는 단점이 있다.
*동적 쿼리
1. BooleanBuilder 사용
@Test
public void dynamicQuery_BooleanBuilder() {
String usernameParam = "member1";
Integer ageParam = null;
List<Member> result = searchMember1(usernameParam, ageParam);
Assertions.assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember1(String usernameCond, Integer ageCond) {
BooleanBuilder builder = new BooleanBuilder();
//new BooleanBuilder(member.username.eq("member1")) 이렇게 기본값을 지정할 수도 있다.
if (usernameCond != null) {
builder.and(member.username.eq(usernameCond));
}
if (ageCond != null) {
builder.and(member.age.eq(ageCond));
}
return queryFactory
.selectFrom(member)
.where(builder)
.fetch();
}
2. where 다중파라미터 사용
@Test
public void dynamicQuery_WhereParam() {
String usernameParam = "member1";
Integer ageParam = 10;
List<Member> result = searchMember2(usernameParam, ageParam);
Assertions.assertThat(result.size()).isEqualTo(1);
}
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
.where(usernameEq(usernameCond), ageEq(ageCond))
.fetch();
}
private BooleanExpression usernameEq(String usernameCond) { //나중에 조립하기 위해서는 BooleanExpression타입으로 리턴타입을 받아야 한다.
return usernameCond != null ? member.username.eq(usernameCond) : null;
}
private BooleanExpression ageEq(Integer ageCond) {
return ageCond != null ? member.age.eq(ageCond) : null;
}
where 다중 파라미터사용의 특징
1. where 조건에 null값은 무시된다.
2. 메서드를 다른 쿼리에서도 재활용 할 수 있다.
3. 쿼리 자체의 가독성이 높아진다.
*벌크성 쿼리
벌크성 쿼리란? JPA의 더티체킹(변경감지)을 사용한 데이터 수정은 각각 일어나기 때문에 쿼리가 하나씩 나가는 단점이 있다. 벌크성 쿼리는 일반 SQL문 처럼 한번에 여러개의 데이터를 수정할 수 있게 해주는 기능이다. 다만 벌크성 쿼리는 JPA의 영속성컨텍스트와 전혀 관계없이 동작하기 때문에 데이터가 일치하지 않는 경우가 생길 수 있다. 이 때문에 벌크성 쿼리를 실행한 후에는 영속성컨텍스트를 완전히 초기화 시켜주는 것이 관례이다.
queryFactory
.update(member)
.set(member.username, "memberA")
.where(member.username.eq("member1"))
.execute();
'JPA > QueryDSL' 카테고리의 다른 글
스프링 부트 5.0 Querydsl 설정 변경 (0) | 2023.05.30 |
---|---|
QueryDSL 중급문법 (0) | 2022.02.07 |
QueryDSL 기본문법 (0) | 2022.02.07 |
Querydsl 실무활용 (0) | 2021.10.01 |
Querydsl 기본문법 (0) | 2021.10.01 |