Querydsl - (3)

bp.chys·2020년 6월 16일
0

JPA

목록 보기
13/15

프로젝션

-프로젝션이란 객체를 반환하는 것이 아니라, 원하는 필드만 뽑아서 DTO로 반환하는 것을 말한다.

프로젝션 대상이 하나

List<String> result = queryFactory
        .select(member.username)
        .from(member)
        .fetch();
  • 프로젝션 대상이 하나면 타입을 명확하게 지정할 수 있다.
  • 프로젝션 대상이 둘 이상이면 튜블이나 DTO로 조회

튜플(tuple) 조회

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);
    System.out.println("username = " + username);
    System.out.println("age = " + age);
}

DTO 조회

1) 프로퍼티 접근

List<MemberDto> result = queryFactory
        .select(Projections.bean(MemberDto.class,
                member.username,
                member.age))
        .from(member)
        .fetch();

2) 필드 직접 접근

List<MemberDto> result = queryFactory
        .select(Projections.fields(MemberDto.class,
                member.username,
                member.age))
        .from(member)
        .fetch();

2-1) 별칭이 다를때

List<UserDto> fetch = queryFactory
        .select(Projections.fields(UserDto.class,
                member.username.as("name"),
                ExpressionUtils.as(
                    JPAExpressions
                            .select(memberSub.age.max())
                            .from(memberSub), "age")
                )
        ).from(member)
        .fetch();
  • 프로퍼티나, 필드 접근 생성 방식에서 이름이 다를 때 해결 방안
  • ExpressionUtils.as(source, alias) : 필드나, 서브 쿼리에 별칭 적용

3) 생성자 사용

List<MemberDto> result = queryFactory
        .select(Projections.constructor(MemberDto.class,
                member.username,
                member.age))
        .from(member)
        .fetch();

DTO에 @QueryProjection 어노테이션을 사용하면 DTO도 Q파일을 생성할 수 있어서 new QDTO로 컴파일 시점에 오류를 검사할 수 있고 어떤 인자가 생성자로 필요한지도 알기가 수월하다. 하지만 이는 DTO가 Querydsl에 의존해야 하는 단점이 있기 때문에 선택적으로 사용하기 바란다.

동적 쿼리

  • BooleanBuilder를 활용하는 방법과 where 다중 파라미터를 사용하는 방법이 있다.
  • 후자가 가독성이 더 좋으므로 후자만 언급한다.
@Test
public void dynamic_whereParam() throws Exception {
    String usernameParam = "member1";
    Integer ageParam = 10;
    
    List<Member> result = searchMember(usernameParam, ageParam);
    Assertions.assertThat(result.size()).isEqualTo(1);
}

private List<Member> searchMember(String usernameCond, Integer ageCond) {
    return queryFactory
            .selectFrom(member)
            .where(usernameEq(usernameCond), ageEq(ageCond))
            .fetch();
}

private BooleanExpression usernameEq(String usernameCond) {
    return usernameCond != null ? member.username.eq(usernameCond) : null;
}

private BooleanExpression ageEq(Integer ageCond) {
    reeturn ageCond != null ? member.age.eq(age.cond) : null;
}
  • where 조건에 null 값은 무시된다.
  • 메서드를 다른 쿼리에서도 재활용 가능
  • 쿼리 자체의 가독성이 높아진다.

수정, 삭제 벌크 연산

수정

long count = queryFactory
        .update(member)
        .set(member.username, "비회원")
        .where(member.age.lt(28))
        .execute();

삭제

long count = queryFactory
        .delete(member)
        .where(member.age.gt(18))
        .execute();
  • JPQL 배치와 마찬가지로, 영속성 컨텍스트에 있는 엔티티를 무시하고 실행되기 때문에 배치 쿼리를 실행하고 나면 영속성 컨텍스트를 초기화하는 것이 안전하다.
profile
하루에 한걸음씩, 꾸준히

0개의 댓글