- 프로젝션과 결과 반환 - 기본
- 프로젝션 : select 대상 지정
- 프로젝션 대상이 하나
List<String> result = queryFactory
.select(member.username)
.from(member)
.fetch();
- 프로젝션 대상이 하나면 타입을 명확하게 지정할 수 있다.
- 프로젝션 대상이 둘 이상이면 Tuple이나 DTO로 조회해야 한다.
- 튜플 조회
- 프로젝션 대상이 둘 이상일 때 사용한다.
@Test
public void 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 조회
- Querydsl 빈 생셩(Bean population)
- 결과를 DTO 반환할 때 사용
1. 프로퍼티 접근
2. 필드 직접 접근
3. 생성자 사용
1. 프로퍼티 접근 - Setter
@Test
public void findDtoBySetter() {
List<MemberDto> result = queryFactory
.select(Projections.bean(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
- Projections.bean을 이용하여 DTO 클래스를 작성해주고, 해당 클래스에서 원하는 필드를 가져다가 사용하는 방법이다.
2. 필드 직접 접근
@Test
public void findDtoByField() {
List<MemberDto> result = queryFactory
.select(Projections.fields(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
- 필드 직접 접근 방식은 말 그대로 필드에 직접 접근하는 방식이다. Member 엔티티에 있는 값을 DTO 필드에 직접 주입하는 방식이다.
- 별칭이 다를 때
- MemberDTO처럼 Member 엔티티의 속성 명을 그대로 사용하는 DTO는 상관없지만 새롭게 생성되는 DTO에 필드명이 다르게 되면 추가적으로 작업을 해주어야 한다.
- UserDto
@Data
public class UserDto {
private String name;
private int userage;
public UserDto() {
}
public UserDto(String name, int userage) {
this.name = name;
this.userage = userage;
}
}
- 위와 같이 UserDto에 필드명이 username이 아닌 name에 값을 age가 아닌 userage에 값을 넣으려 한다.
- 일반적인 별칭에 바로 넣는 방식
@Test
public void findUserDto2() {
QMember memberSub = new QMember("memberSub");
List<UserDto> result = queryFactory
.select(Projections.fields(UserDto.class,
member.username.as("name"),
member.age.as("userage")
))
.from(member)
.fetch();
for (UserDto userDto : result) {
System.out.println("userDto = " + userDto);
}
}
- 서브 쿼리를 이용하는 방식
@Test
public void findUserDto() {
QMember memberSub = new QMember("memberSub");
List<UserDto> result = queryFactory
.select(Projections.fields(UserDto.class,
member.username.as("name"),
ExpressionUtils.as(JPAExpressions
.select(memberSub.age.max())
.from(memberSub), "userage")
))
.from(member)
.fetch();
- as를 통해 별칭을 지정하여 값을 넣어준다.
3. 생성자 사용
@Test
public void findDtoByConstructor() {
List<MemberDto> result = queryFactory
.select(Projections.constructor(MemberDto.class,
member.username,
member.age
))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
@Test
public void findUserByConstructor() {
List<UserDto> result = queryFactory
.select(Projections.constructor(UserDto.class,
member.username,
member.age))
.from(member)
.fetch();
for (UserDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
- 생성자를 사용하는 방식은 원하는 필드가 포함되어 있는 생성자만 생성해 준다면 별칭을 이용하지 않고 엔티티의 값만 이용해서 DTO에 값을 넣어 반환 할 수 있다.
- UserDto의 필드명이 member 엔티티의 필드명과 다르지만 생성자 위치에 의해 별도의 별칭을 부여하지 않아도 정상적으로 값이 들어가는 것을 확인 할 수 있다.
- 프로젝션과 결과 반환 - @QueryProjection
- MemberDto
@Data
public class MemberDto {
private String username;
private int age;
public MemberDto() {
}
@QueryProjection
public MemberDto(String username, int age) {
this.username = username;
this.age = age;
}
}
- 생성자 위에 @QueryProjection을 부여해주게 되면 해당 필드에 맞게 QMemberDto를 Querydsl에서 생성한다.
- Test 코드
@Test
public void findDtoByQueryProjection() {
List<MemberDto> result = queryFactory
.select(new QMemberDto(member.username, member.age))
.from(member)
.fetch();
for (MemberDto memberDto : result) {
System.out.println("memberDto = " + memberDto);
}
}
- @QueryProjection 방식 또한 (new QMemberDto)를 통해 새롭게 객체를 생성하는 약간의 차이 빼고는 기존의 필드, 생성자 방식과 유사하고 쿼리, 결과물 또한 동일하다.
- 하지만 다른 방식과 다른 @QueryProjection의 장점이 있다.
- 생성자 방식
- @QueryProjection 방식
- 생성자 방식의 경우 해당 생성자 필드에 없는 값이 들어가도 컴파일러로 타입을 체크할 수 없기 때문에 런타임에서 오류가 발생한다.
- 하지만 @QueryProjection의 경우 컴파일러가 타입을 체크하기 때문에 실행전에 오류를 발견할 수 있다는 장점이 있다.
- 하지만 @QueryProjection의 경우 Querydsl 어노테이션을 유지해야 하기 때문에 종속적이고, DTO까지 Q 파일을 생성해야 하는 단점이 존재한다.
출처 : 인프런 - 김영한(실전! Querydsl)
'Programming > Querydsl' 카테고리의 다른 글
Querydsl - 중급 문법 (3) 수정, 삭제 벌크 연산 / SQL function 호출 (0) | 2023.07.28 |
---|---|
Querydsl - 중급 문법 (2) 동적 쿼리 (0) | 2023.07.28 |
Querydsl - 기본 문법 (3) (조인, 서브 쿼리, Case문, 상수, 문자 더하기) (0) | 2023.07.27 |
Querydsl - 기본 문법 (2) (결과 조회, 정렬, 페이징, 집합) (0) | 2023.07.27 |
Querydsl - 기본 문법 (1) (기본 Q 타입, 검색, AND) (0) | 2023.07.26 |