[SpringData] Projection

KMS·2022년 4월 27일
0

SpringData

목록 보기
7/9

엔티티 대신 DTO로 클라이언트에 반환할때, 엔티티를 DB로 받아서 변환하는 작업을 하지 않고 DTO로 바로 반환 받을 수 있는 방법입니다.

Interface 기반 Projection

UsernameOnly

public interface UsernameOnly {
    String getUsername();
}

Repository

List<UsernameOnly> findProjectionByUsername(String username);

Test

List<UsernameOnly> members = memberDataRepository.findProjectionByUsername("MemberB");

반환 받을 타입을 UsernameOnly 인터페이스로 두고, 해당 인터페이스에서는 원하는 속성의 Getter 형식의 이름으로 메서드를 선언해주면, DB에서 해당 Column의 값들만 반환해 줍니다.
여기서 중요한 것은 실행되는 쿼리문도 해당 Column만 가져오는 쿼리문이 실행 됩니다.(select member member0 where member0.username='MemberB')

Class 기반 Projection (+Generic)

UsernameAndAgeDTO

private String username;
    private int age;

    public UsernameAndAgeDTO(String username, int age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public int getAge() {
        return age;
    }

Repository

<T> List<T> findProjectionGenericByUsernameAndAge(String username, int age, Class<T> type);

Test

List<UsernameAndAgeDTO> membersGeneric = memberDataRepository.findProjectionGenericByUsernameAndAge("MemberB", 35, UsernameAndAgeDTO.class);

인터페이스 대신 클래스로 DTO를 개발하고 싶으면, 클래스로 개발하시고, 인터페이스로 하셨을때랑 똑같이 작동하고, 똑같이 사용하시면 됩니다. 다만, 이번 예제에서는 리포지토리에서 Generic을 사용해서 스펙의 변동에 따라 사용하는 DTO가 달라질 경우, 리포티토리에서 반환 타입을 바꾸지 않고도 제대로 작동되는 것 방법을 알아보았습니다.
해당 예제에서 실행되는 쿼리문은 'select member0.username as col_0_0, member0.age as col_1_0 from member member0 where member0.username='MemberB' and member0_.age=35' 으로, 반환받고자 하는 Column에서만 값을 가져오는 것을 확인 할 수 있습니다.

단점:

Projection은 Join할 경우에는 사용을 추천하지 않습니다. 왜냐하면, 예를 들어, A가 B를 참조하고 있는 구조에서, A가 참조하는 B에서 특정 Column의 값을 가져오고 싶을때, 무조건 A LEFT OUTER JOIN B로 실행되고, B의 모든 Column들을 가져온 후, 그 중에서 필요로 했던 특정 Column을 반환해주기 때문에, 최적화를 할 수가 없습니다.
ex:
select m.username as col0_0, t.teamid as col1_0, t.teamid as teamid12, t.name as name22 from member m left outer join team t on m.teamid=t.teamid where m.username=?
예시 쿼리문을 보시면 member LEFT OUTER JOIN team을 해서 team의 모든 Column들을 가져 왔습니다. 하지만, 저희가 필요했던것은 team.name 뿐이였습니다. 그러나, Projection을 사용할 경우 team의 모든 Column을 가져오기 때문에 앞서 말했듯이 최적화를 할 수가 없습니다.

profile
Student at Sejong University Department of Software

0개의 댓글