Table of Contents
Projections 의 객체 생성방법 3가지
Projections 사용법에 대해 오해를 불러올 수 있다는 의견이 있어 문서 추가작성합니다.
@QueryProjection 을 이용한 객체생성
생성되는 QClass 에 있는 생성자를 이용하는 방식입니다.
기존 객체가 생성자를 이용해 생성되고 있었다면 선택의 여지는 없고,
이방법으로만 생성해야 합니다.
현재 시점에서는 어떤 방법을 사용한다고 해도 상관없을 수 있지만,
추후에 생성자에 어떤 로직이 추가될지 알수 없으므로,
선택의 여지가 없습니다.
@Getter
@Setter
@NoArgsConstructor
public class UserGroupByDto {
private String username;
private Long count;
@QueryProjection
public UserGroupByDto(String username, Long count) {
this.username = username;
this.count = count;
}
}
public List<UserGroupByDto> groupBy() {
return jpaQueryFactory
.select(new QUserGroupByDto(
user.username
, user.count().as("count")
)
)
.from(user)
.groupBy(user.username)
.orderBy(user.username.asc())
.fetch();
}
@Setter 를 이용한 객체생성
@Setter 를 이용해 객체를 생성합니다.
생성자를 PROTECTED 로 지정해 차후에도,
생성자를 추가하지 못하게 하면 더 안전한 코드가 됩니다.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor(access = AccessLevel.PROTECTED)
public class UserGroupByDto {
private String username;
private Long count;
}
public List<UserGroupByDto> groupBy() {
return jpaQueryFactory
.select(
Projections.bean(
UserGroupByDto.class
, user.username
, user.count().as("count")
)
)
.from(user)
.groupBy(user.username)
.orderBy(user.username.asc())
.fetch();
}
fields 를 이용한 객체생성
@Setter 를 생성하지 않고 객체의 데이타를 직접 입력합니다.
불필요할 가능성이 높은 @Setter 추가하지 않아도 된다는 장점이 있습니다.
하지만 객체의 은닉성 원칙을 해치면서 얻어내는 결과라는 점에서 개인적으로는 선호하지 않습니다.
(일종의 편법으로 java 가 언어 레벨에서 막아버릴 수도 있고…
개인적으로는 막혔으면 합니다.)
@Getter
@NoArgsConstructor
public class UserGroupByDto {
private String username;
private Long count;
private UserGroupByDto(String username, Long count) {
// Projections 을 이용해 객체 생성할 것
throw new RuntimeException();
}
}
public List<UserGroupByDto> groupBy() {
return jpaQueryFactory
.select(
Projections.fields(
UserGroupByDto.class
, user.username
, user.count().as("count")
)
)
.from(user)
.groupBy(user.username)
.orderBy(user.username.asc())
.fetch();
}