특징: 클래스의 필드에 있는것 기반으로 사용가능
특징: Class의 setter 기반으로 작동 및 setter열어야함.
불변 객체 지향한다면 권장X
특징: 생성자 기반,이때 바인딩 방식이용으로 생성자 넘기는 순서 달라질 수 있다.(클래스가 가지고있는 생성자이용X)
특징: 생성자에 @QueryProjection어노테이션 붙이면 자동으로 생성되고 실제 클래스가 선언한 생성자기반으로 작성됨. 따라서 제일권장됨.
Query dsl을 사용하였을때 Join과 관련된 복잡한 변환과 관련되서 알아보자.
1. 두가지 도메인의 1:N Join
public List<Family> findFamily() {
return queryFactory
.select(Projections.fields(Family.class,
parent.name,
parent.children///....1
))
.from(parent)
.leftJoin(parent.children, child)//....2
.fetch();
}
다음과 같은 쿼리를 날리게 되면 어떻게 될까? 내가 지금 Projection하고 싶은 필드는 부모의 이름과 부모의 아이들이다. 하지만 2가지 이유로 실패및 문제가 생긴다.
첫번째, 필드에 List형식을 넣으면 자동으로 변환을 하지 못한다.
두번째, parent children을 찾는작업과 left(parent,child,child)를 찾는 비효율적인 작업을한다.
해결방법
1. Entity그대로 받아온후 stream()으로 변환
Entity를 그대로 받아오면 자동으로 LeftOuterJoin으로 실행이되고 이를 다시 변환해서 쓰는 방법을 사용한다.
public List<Family> findFamily() {
List<Parent> parents = queryFactory
.selectFrom(parent)
.leftJoin(parent.children, child).
.fetch();
return parents.stream()
.map(p -> new Family(p.getName(), p.getChildren()))
.collect(Collectors.toList());
}
Result Aggregation
query dsl에서 지원하는 결과집합을 사용하면 특정키를 기준으로 그룹화시킬 수 있다.
import static com.querydsl.core.group.GroupBy.groupBy;
import static com.querydsl.core.group.GroupBy.list;
public List<Family> findFamily() {
Map<Parent, List<Child>> transform = queryFactory
.from(parent)
.leftJoin(parent.children, child)
.transform(groupBy(parent).as(list(child)));
return transform.entrySet().stream()
.map(entry -> new Family(entry.getKey().getName(), entry.getValue()))
.collect(Collectors.toList());
}
이때 transform은 groupby기준으로 key로 list를 value로 지정해준다. 이렇게 할경우 **LazyLoading**이 됩니다.
**참고 출처:**
1. 1:N Join:https://jojoldu.tistory.com/342