QueryDsl
결과값의 종류
1. 단일 결과 조회
• fetchOne(): 하나의 결과만 반환.
• fetchFirst(): 결과 중 첫 번째 것만 반환.
Member member = queryFactory
.selectFrom(QMember.member)
.where(QMember.member.username.eq("user1"))
.fetchOne();
주의사항: 결과가 없으면 null을 반환하고, 두 개 이상의 결과가 있으면 NonUniqueResultException이 발생합니다.
2. 다중 결과 조회
• fetch(): 리스트 형태로 여러 결과를 반환.
List<Member> members = queryFactory
.selectFrom(QMember.member)
.where(QMember.member.age.gt(20))
.fetch();
3. 페이징 결과 조회
• fetchResults(): 결과 리스트와 전체 개수를 함께 반환.
• fetchCount(): 전체 결과 개수만 반환.
QueryResults<Member> results = queryFactory
.selectFrom(QMember.member)
.offset(0)
.limit(10)
.fetchResults();
long total = results.getTotal();
List<Member> members = results.getResults();
4. 튜플(Tuple) 조회
• 여러 필드를 선택하여 Tuple 형태로 반환.
List<Tuple> result = queryFactory
.select(QMember.member.username, QMember.member.age)
.from(QMember.member)
.fetch();
for (Tuple tuple : result) {
String username = tuple.get(QMember.member.username);
Integer age = tuple.get(QMember.member.age);
}
5. DTO 조회
• 원하는 DTO 형태로 결과를 매핑하여 반환합니다.
• 방법:
• 프로퍼티 접근: Projections.bean()
• 필드 직접 접근: Projections.fields()
• 생성자 사용: Projections.constructor()
• @QueryProjection 사용: 컴파일 시 타입 체크 가능
List<MemberDto> result = queryFactory
.select(Projections.bean(MemberDto.class,
QMember.member.username,
QMember.member.age))
.from(QMember.member)
.fetch();
1. 프로퍼티 접근: Projections.bean()
사용 시기
• DTO에 Getter와 Setter 메서드가 있을 때 사용.
• 필드명과 DTO의 프로퍼티명이 정확히 일치할 때 효과적.
장점
• 코드 가독성이 높습니다.
• DTO의 프로퍼티에 값을 설정하므로, 객체 지향 원칙에 부합함.
• Setter 메서드를 통해 값을 주입하므로, 캡슐화를 유지할 수 있다.
단점
• DTO에 기본 생성자와 Setter 메서드가 필요하다.
• 필드명이 일치하지 않으면 매핑이 되지 않는다.
• 런타임 시에만 오류를 발견할 수 있으며, 컴파일 시 타입 체크가 불가능하다.
List<MemberDto> result = queryFactory
.select(Projections.fields(MemberDto.class,
QMember.member.username,
QMember.member.age))
.from(QMember.member)
.fetch();
2. 필드 직접 접근: Projections.fields()
사용 시기
• DTO의 필드가 public이거나 접근 가능할 때 사용.
• Getter와 Setter가 없거나 사용하기 어려운 경우에 유용.
장점
• Setter 메서드 없이도 값을 주입할 수 있다.
• 필드명만 일치하면 되므로, 프로퍼티 접근보다 유연하다.
단점
• 캡슐화가 약화됩니다. 필드에 직접 접근하므로, 객체 지향 원칙에 어긋날 수 있다.
• 필드명이 일치하지 않으면 매핑이 되지 않는다.
• 마찬가지로 컴파일 시 타입 체크가 불가능하다.
List<MemberDto> result = queryFactory
.select(Projections.constructor(MemberDto.class,
QMember.member.username,
QMember.member.age))
.from(QMember.member)
.fetch();
3. 생성자 사용: Projections.constructor()
사용 시기
• DTO에 원하는 필드를 받는 생성자가 있을 때 사용.
• **불변 객체(Immutable Object)**를 생성하고자 할 때 유용.
장점
• Setter나 필드 접근 없이도 값을 주입할 수 있다.
• DTO를 불변 객체로 유지할 수 있다.
• 생성자를 통해 객체 생성이 이루어지므로, 객체의 일관성을 보장.
단점
• 파라미터의 타입과 순서가 정확히 일치해야 한다.
• 필드명이 달라도 타입과 순서로 매핑되므로, 실수할 가능성이 있다.
• 런타임 시에만 오류를 발견할 수 있으며, 컴파일 시 타입 체크가 불가능하다.
List<MemberDto> result = queryFactory
.select(new QMemberDto(QMember.member.username, QMember.member.age))
.from(QMember.member)
.fetch();
4. @QueryProjection 사용
사용 시기
• 컴파일 시 타입 체크를 통해 안전한 코드를 작성하고자 할 때 사용.
• QueryDSL에 의존성이 허용되는 DTO에 적용 가능.
장점
• 컴파일 시점에 타입 체크가 가능하여, 오류를 사전에 방지할 수 있다.
• 코드 자동 완성 등 IDE의 지원을 받을 수 있다.
• 생성자 파라미터의 타입과 순서를 정확히 맞출 필요가 없다.
단점
• DTO에 QueryDSL 어노테이션을 추가해야 하므로, QueryDSL에 의존성이 생긴다.
• Q파일 생성을 위해 추가적인 빌드 설정이 필요하다.
• 프로젝트 규모가 커질수록 빌드 시간이 증가할 수 있다.
'Spring > QueryDsl' 카테고리의 다른 글
태태개발일지 - QueryDSL (1) | 2024.09.29 |
---|