DTO를 반환하는 방법이 크게 3가지가 있다.
생성자 + @QueryProjection
프로젝션을 이용한 방법 중에 가장 깔끔한 방법일 수 있다.
@QueryProjection을 이용해 DTO도 Q타입의 클래스를 만들어서 이를 이용해 바로 만드는 방법이다.
Q타입의 클래스를 제공해주니 type-safe하다는 장점이 있다.
@QueryProjection을 이용해 생성하는 방법
@Test
void projectionWithJpa(){
//given
//when
List<MemberDto> result = em.createQuery(
"select new com.study.querydsl.dto.MemberDto(m.username, m.age)" +
"from Member m", MemberDto.class
)
.getResultList();
//then
for (MemberDto memberDto : result){
System.out.println(memberDto.toString());
}
}
@Test
void findDtoByQueryProjection(){
//given
//when
List<MemberDto> result = queryFactory
.select(new QMemberDto(member.username, member.age))
.from(member)
.fetch();
//then
for (MemberDto memberDto : result) {
System.out.println(memberDto.toString());
}
}
실행시에 쿼리 문장이 만들어져 실행되는 쿼리문을 동적 쿼리라고 하는데, 동적으로 변수를 받아서 쿼리가 완성되는 걸 말한다.
Predicate
를 파라미터로 이용하는 방법BooleanBuilder
를 이용하는 방법BooleanExpression
을 쓰는 방법 (Where 다중 파라미터 사용 )where 파라미터 이용 예제 (BooleanExpression)
@Test
void dynamicQueryUsingWhereParameter(){
//given
String usernameParam = "member1";
Integer ageParam = 10;
//when
List<Member> result = searchMember2(usernameParam, ageParam);
//then
assertEquals(1, result.size());
}
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
return queryFactory
.selectFrom(member)
.where(usernameEq(usernameCond), ageEq(ageCond))
.fetch();
}
private Predicate usernameEq(String usernameCond) {
if(usernameCond == null) return null;
return member.username.eq(usernameCond);
}
private Predicate ageEq(Integer ageCond) {
if(ageCond == null) return null;
return member.age.eq(ageCond);
}
where 파라미터 조립 예제
@Test
void dynamicQueryUsingWhereParameter2(){
//given
String usernameParam = "member1";
Integer ageParam = 10;
//when
List<Member> result = searchMember3(usernameParam, ageParam);
//then
assertEquals(1, result.size());
}
private List<Member> searchMember3(String usernameParam, Integer ageParam) {
return queryFactory
.selectFrom(member)
.where(allEq(usernameParam, ageParam))
.fetch();
}
private BooleanExpression allEq(String usernameParam, Integer ageParam) {
return usernameEq1(usernameParam).and(ageEq(ageParam));
}
private BooleanExpression usernameEq1(String usernameCond) {
if(usernameCond == null) return null;
return member.username.eq(usernameCond);
}
private BooleanExpression ageEq1(Integer ageCond) {
if(ageCond == null) return null;
return member.age.eq(ageCond);
}
쿼리 한번으로 대량의 데이터를 수정하는 방식에 관한 것이다. 이를 벌크 연산이라고 한다.
벌크 연산 예제 - 수정
@Test
void bulkUpdate(){
//given
//when
long count = queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
//then
assertEquals(2, count);
}
벌크 수정 연산 후 데이터 가져오기 - 영속성 컨텍스트에서 가져오므로 반영이 안됨
@Test
@DisplayName("벌크 수정 연산 후 데이터 가져오기 - 영속성 컨택스트에서 가져오므로 반영이 안됨.")
void bulkUpdateAndFetch(){
//given
//when
queryFactory
.update(member)
.set(member.username, "비회원")
.where(member.age.lt(28))
.execute();
List<Member> result = queryFactory
.selectFrom(member)
.fetch();
//then
for (Member member : result) {
System.out.println(member.getUsername() + " " + member.getAge());
}
}
벌크 연산 - 모든 나이 + 1하기
@Test
void bulkAdd(){
//given
//when
long count = queryFactory
.update(member)
.set(member.age, member.age.add(1))
.execute();
//then
assertEquals(4, count);
}
벌크 연산 - 모든 나이 * 2하기
@Test
void bulkMultiply(){
//given
//when
long count = queryFactory
.update(member)
.set(member.age, member.age.multiply(2))
.execute();
//then
assertEquals(4, count);
}
벌크 연산 - 18세 이상 모든 회원 지우기
@Test
void bulkDelete(){
//given
//when
long count = queryFactory
.delete(member)
.where(member.age.gt(18))
.execute();
//then
}