Skip to content

Commit db272be

Browse files
committed
querydsl - dto, dynamic query, bulk
1 parent 318a8c6 commit db272be

File tree

4 files changed

+320
-1
lines changed

4 files changed

+320
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package study.querydsl.dto;
2+
3+
import com.querydsl.core.annotations.QueryProjection;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
@Data
9+
@NoArgsConstructor
10+
public class MemberDto {
11+
12+
private String username;
13+
private int age;
14+
15+
@QueryProjection
16+
public MemberDto(String username, int age) {
17+
this.username= username;
18+
this.age= age;
19+
}
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package study.querydsl.dto;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
@Data
8+
@NoArgsConstructor
9+
@AllArgsConstructor
10+
public class UserDto {
11+
12+
private String username;
13+
private int age;
14+
}

querydsl/src/main/resources/application.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ spring:
1212
hibernate:
1313
show_sql: true
1414
format_sql: true
15+
jooq:
16+
sql-dialect: org.hibernate.dialect.MySQL8Dialect
1517

1618
logging.level:
17-
org.hibernate.SQL: debug
19+
org.hibernate.SQL: debug

querydsl/src/test/java/study/querydsl/QuerydslBasicTest.java

+282
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
package study.querydsl;
22

3+
import com.querydsl.core.BooleanBuilder;
34
import com.querydsl.core.QueryResults;
45
import com.querydsl.core.Tuple;
56
import com.querydsl.core.types.Expression;
7+
import com.querydsl.core.types.ExpressionUtils;
8+
import com.querydsl.core.types.Predicate;
9+
import com.querydsl.core.types.Projections;
10+
import com.querydsl.core.types.dsl.BooleanExpression;
611
import com.querydsl.core.types.dsl.Expressions;
712
import com.querydsl.jpa.JPAExpressions;
813
import com.querydsl.jpa.impl.JPAQuery;
@@ -11,7 +16,11 @@
1116
import org.junit.jupiter.api.Test;
1217
import org.springframework.beans.factory.annotation.Autowired;
1318
import org.springframework.boot.test.context.SpringBootTest;
19+
import org.springframework.test.annotation.Commit;
1420
import org.springframework.transaction.annotation.Transactional;
21+
import study.querydsl.dto.MemberDto;
22+
import study.querydsl.dto.QMemberDto;
23+
import study.querydsl.dto.UserDto;
1524
import study.querydsl.entity.*;
1625

1726
import javax.persistence.EntityManager;
@@ -429,5 +438,278 @@ public void constant() {
429438
}
430439
}
431440

441+
// 프로젝션 대상 하나 인경우
442+
@Test
443+
public void simpleProjection() {
444+
List<String> usernames = jpaQueryFactory
445+
.select(member.username)
446+
.from(member)
447+
.fetch();
448+
449+
List<Member> members = jpaQueryFactory
450+
.selectFrom(member)
451+
.fetch();
452+
453+
for (String username : usernames) {
454+
System.out.println("username = " + username);
455+
}
456+
457+
for (Member member1 : members) {
458+
System.out.println("member1 = " + member1);
459+
}
460+
}
461+
462+
// 투플의 경우, 레파지토리 계층에서만 사용 권장
463+
// dto로 변환 후 사용권장
464+
@Test
465+
public void tupleProjection() {
466+
List<Tuple> tuples = jpaQueryFactory
467+
.select(member.username, member.age)
468+
.from(member)
469+
.fetch();
470+
471+
for (Tuple tuple : tuples) {
472+
System.out.println("tuple.get(member.username) = " + tuple.get(member.username));
473+
System.out.println("tuple.get(member.age) = " + tuple.get(member.age));
474+
}
475+
}
476+
477+
// jpa dto 조회
478+
@Test
479+
public void findDto() {
480+
List<MemberDto> memberDtos = em.createQuery("select new study.querydsl.dto.MemberDto(m.username, m.age) from Member m", MemberDto.class)
481+
.getResultList();
482+
for (MemberDto memberDto : memberDtos) {
483+
System.out.println("memberDto = " + memberDto);
484+
}
485+
}
486+
487+
488+
// dto => 기본생성자 존재해야함
489+
// setter 주입
490+
// getter, setter 존재해야함
491+
@Test
492+
public void findDtoByQuerydsl() {
493+
List<MemberDto> memberDtos = jpaQueryFactory
494+
.select(Projections.bean(MemberDto.class, member.username, member.age))
495+
.from(member)
496+
.fetch();
497+
for (MemberDto memberDto : memberDtos) {
498+
System.out.println("memberDto = " + memberDto);
499+
}
500+
}
501+
502+
// 필드 입 : getter, setter 없어도됨
503+
@Test
504+
public void findDtoByFields() {
505+
List<MemberDto> memberDtos = jpaQueryFactory
506+
.select(Projections.fields(MemberDto.class, member.username, member.age))
507+
.from(member)
508+
.fetch();
509+
for (MemberDto memberDto : memberDtos) {
510+
System.out.println("memberDto = " + memberDto);
511+
}
512+
}
513+
514+
//생성자 주입
515+
@Test
516+
public void findDtoByConstructor() {
517+
List<MemberDto> memberDtos = jpaQueryFactory
518+
.select(Projections.constructor(MemberDto.class, member.username, member.age))
519+
.from(member)
520+
.fetch();
521+
for (MemberDto memberDto : memberDtos) {
522+
System.out.println("memberDto = " + memberDto);
523+
}
524+
}
525+
526+
// 필드주입 - 필드이름 = 엔티티이름 같아야함
527+
// 다를 경우, as 사용
528+
@Test
529+
public void findDtoByUserDto() {
530+
QMember memberSub = new QMember("memberSub");
531+
532+
List<UserDto> memberDtos = jpaQueryFactory
533+
.select(Projections.fields(UserDto.class, member.username.as("name"),
534+
ExpressionUtils.as(JPAExpressions
535+
.select(memberSub.age.max())
536+
.from(memberSub), "age"
537+
)
538+
)
539+
)
540+
.from(member)
541+
.fetch();
542+
for (UserDto memberDto : memberDtos) {
543+
System.out.println("memberDto = " + memberDto);
544+
}
545+
}
546+
547+
// 생성자 주입 - 타입만 같으면 가능
548+
@Test
549+
public void findDtoByUserDtoByConstructor() {
550+
QMember memberSub = new QMember("memberSub");
551+
552+
List<UserDto> memberDtos = jpaQueryFactory
553+
.select(Projections.constructor(UserDto.class, member.username,
554+
JPAExpressions
555+
.select(memberSub.age.max())
556+
.from(memberSub)
557+
558+
)
559+
)
560+
.from(member)
561+
.fetch();
562+
for (UserDto memberDto : memberDtos) {
563+
System.out.println("memberDto = " + memberDto);
564+
}
565+
}
566+
567+
568+
// 컴파일 에러 잡기 가능
569+
// dto -> querydsl에 대한 의존성이 생김 (순수한 dto라 볼수없음)
570+
// 아키텍쳐에 따라 유연하게 결정
571+
@Test
572+
public void findDtoByQueryProjection() {
573+
List<MemberDto> memberDtos = jpaQueryFactory
574+
.select(new QMemberDto(member.username, member.age))
575+
.from(member)
576+
.fetch();
577+
for (MemberDto memberDto : memberDtos) {
578+
System.out.println("memberDto = " + memberDto);
579+
}
580+
}
581+
582+
583+
// 동적쿼리 - 이름,나이 존재하면 where 절에 조건넣음
584+
@Test
585+
public void dynamicQuery_BooleanBuilder() {
586+
String usernameParam = "member1";
587+
Integer ageParam = null;
588+
589+
List<Member> result = searchMember1(usernameParam, ageParam);
590+
assertThat(result.size()).isEqualTo(1);
591+
}
592+
593+
//
594+
private List<Member> searchMember1(String usernameCond, Integer ageCond) {
595+
BooleanBuilder builder = new BooleanBuilder();
596+
if (usernameCond != null) {
597+
builder.and(member.username.eq(usernameCond));
598+
}
599+
600+
if (ageCond != null) {
601+
builder.and(member.age.eq(ageCond));
602+
}
603+
604+
List<Member> result = jpaQueryFactory
605+
.selectFrom(member)
606+
.where(builder)
607+
.fetch();
608+
609+
return result;
610+
}
611+
612+
// where 절에 null 이면 무시
613+
// where 절 가독성 좋음
614+
//querydsl - 재사용성 가능 (자바코드이기 때문에)
615+
@Test
616+
public void dynamicQueryWhere() {
617+
String usernameParam = "member1";
618+
Integer ageParam = null;
619+
620+
List<Member> result = searchMember2(usernameParam, ageParam);
621+
assertThat(result.size()).isEqualTo(1);
622+
}
623+
624+
private List<Member> searchMember2(String usernameCond, Integer ageCond) {
625+
return jpaQueryFactory
626+
.selectFrom(member)
627+
.where(allEq(usernameCond, ageCond))
628+
.fetch();
629+
}
630+
631+
private BooleanExpression ageEq(Integer ageCond) {
632+
return ageCond != null ? member.age.eq(ageCond) : null;
633+
}
634+
635+
private BooleanExpression usernameEq(String usernameCond) {
636+
return usernameCond != null? member.username.eq(usernameCond) : null;
637+
}
638+
639+
// 컴포지션 가능
640+
private Predicate allEq(String usernameCond, Integer ageCond) {
641+
return usernameEq(usernameCond).and(ageEq(ageCond));
642+
}
643+
644+
//벌크연산
645+
@Test
646+
public void bulkUpdate() {
647+
long count = jpaQueryFactory
648+
.update(member)
649+
.set(member.username, "비회원")
650+
.where(member.age.lt(28))
651+
.execute();
652+
653+
em.clear();
654+
655+
// 나이 1 빼기
656+
// long count2 = jpaQueryFactory
657+
// .update(member)
658+
// .set(member.age, member.age.add(-1))
659+
// .execute();
660+
661+
662+
List<Member> result = jpaQueryFactory
663+
.selectFrom(member)
664+
.fetch();
665+
for (Member member1 : result) {
666+
System.out.println("member1 = " + member1.getUsername());
667+
}
668+
669+
}
670+
671+
//벌크 삭제
672+
@Test
673+
public void deleteBulk() {
674+
long count = jpaQueryFactory
675+
.delete(member)
676+
.where(member.age.lt(18))
677+
.execute();
678+
679+
}
680+
681+
//sql function : ex) replace 함수
682+
@Test
683+
public void sqlFunction() {
684+
List<String> result = jpaQueryFactory
685+
.select(
686+
Expressions.stringTemplate("function('regexp_replace', {0}, {1}, {2})",
687+
member.username,
688+
"member",
689+
"M")
690+
).from(member)
691+
.fetch();
692+
693+
for (String s : result) {
694+
System.out.println("s = " + s);
695+
}
696+
}
697+
698+
// 소문자 함수
699+
@Test
700+
public void sqlFunction2() {
701+
List<String> result = jpaQueryFactory
702+
.select(member.username)
703+
.from(member)
704+
// .where(member.username.eq(Expressions.stringTemplate("function('lower', {0})", member.username)))
705+
.where(member.username.eq(member.username.lower()))
706+
.fetch();
707+
708+
for (String s : result) {
709+
System.out.println("s = " + s);
710+
}
711+
}
712+
713+
432714

433715
}

0 commit comments

Comments
 (0)