스프링데이터 + JPA/QueryDSL

32. 사용자 정의 리포지토리

sdafdq 2023. 12. 4. 02:15

https://qwefdg3.tistory.com/889

 

앞서 배웠던 여기에 쿼리DSL을 쓸 것

 

public interface MemberRepositoryCustom {
    List<MemberTeamDto> search(MemberSearchCondition condition);
}

이름 적당히 해서 인터페이스 만들고,

구현할 메소드 선언 해 주고

 

public class MemberRepositoryImpl implements MemberRepositoryCustom{
    private final JPAQueryFactory query;

    public MemberRepositoryImpl(EntityManager em) {
        this.query = new JPAQueryFactory(em);
    }

    @Override
    public List<MemberTeamDto> search(MemberSearchCondition condition){
        return query.select(new QMemberTeamDto(
                        member.id, member.username, member.age, team.id, team.name
                )).from(member).leftJoin(member.team, team)
                .where(
                        usernameEq(condition.getUsername()),
                        teamNameEq(condition.getTeamName()),
                        ageGoe(condition.getAgeGoe()),
                        ageLoe(condition.getAgeLoe())
                )
                .fetch();
    }

    private BooleanExpression usernameEq(String username){
        return StringUtils.hasText(username) ? member.username.eq(username) : Expressions.TRUE;
    }
    private BooleanExpression teamNameEq(String teamName){
        return StringUtils.hasText(teamName) ? team.name.eq(teamName) : Expressions.TRUE;
    }

    private BooleanExpression ageGoe(Integer ageGoe){
        return ageGoe != null ? member.age.goe(ageGoe) : Expressions.TRUE;
    }
    private BooleanExpression ageLoe(Integer ageLoe){
        return ageLoe != null ? member.age.loe(ageLoe) : Expressions.TRUE;
    }
}

 

우리가 앞서 만들었던 Spring Data JPA이름 + Impl이라는 구현체를 만들어 상속받음.

이게 중요함. 꼭 SpringDataJPA + Impl이라는 이름이여야 함.

 

거기다 이제 구현하면 됨.

 

쿼리 DSL은 그냥 이렇게 Spring Data Repository에 커스텀 리포지토리를 붙일 수 있는 기능을 써서 구현하는 수 밖에 없음.

 

 

아니면, 하다보면 핵심 비즈니스 로직보다는 화면에 맞춘, API맞춘 메소드를 만들어야 할 때가 있음.

 

그 때는 아예 새 리포지토리를 만들기도 함. 그러니까 Member엔티티라면 핵심 비즈니스가 있는 SpringData리포지토리 + 커스텀 리포지토리에, 

아예 @Repository 하면서 화면에 맞춘 Member엔티티를 대상으로 하는 리포지토리를 새로 하나 더 만드는 거임.

 

이게 좋은 점이 핵심 비즈니스 로직은 오래 가지만 화면에 맞춘건 금방금방 바뀌기 때문에 그것만 따로 관리할 수 있음.

즉, 수정의 생명주기가 다르단 말임.

 

 

@Test
public void searchTest(){
    Team teamA = new Team("teamA");
    Team teamB = new Team("teamB");
    em.persist(teamA);
    em.persist(teamB);

    Member member1 = new Member("member1", 10, teamA);
    Member member2 = new Member("member2", 20, teamA);

    Member member3 = new Member("member3", 30, teamB);
    Member member4 = new Member("member4", 40, teamB);

    em.persist(member1);
    em.persist(member2);
    em.persist(member3);
    em.persist(member4);

    MemberSearchCondition condition = new MemberSearchCondition();
    condition.setAgeGoe(20);
    condition.setAgeLoe(40);
    condition.setTeamName("teamB");

    List<MemberTeamDto> result = memberRepository.search(condition);

    assertThat(result).extracting("username").containsExactly("member3","member4");
}

테스트 문제 없이 통과