본문 바로가기
JPA/스프링 DATA JPA

Data JPA 05 쿼리 메서드 - Query, 리포지토리 메서드에 쿼리 정의하기

by 킹차니 2022. 1. 5.

@Query를 사용하면 data jpa 리포지토리에서 아래와 같이 쿼리를 직접 정의할 수 있다.

 

username과 age로 Member를 조회하는 메서드를 작성해보자.

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import study.datajpa.entity.Member;

import java.util.List;

public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query("select m from Member m where m.username = :username and m.age = :age")
    List<Member> findMember(@Param("username") String username, @Param("age") int age);
}

위처럼 @Query안에 직접 쿼리문을 작성할 수 있다.

이러한 방법의 장점은 만약 @Query안에 아래와 같은 오타가 있다면

@Query("select m from Member m where m.useraksudhname = :username and m.age = :age")

어플리케이션 실행 시점에 에러를 발생시켜준다.

위처럼 오타를 의도적으로 내고 실행해보니 아래와 같은 에러가 발생했다.

org.hibernate.QueryException: could not resolve property: useraksudhname of: study.datajpa.entity.Member...(생략)

 

 

 

 

 

특정 username으로 select를 하고 싶다면 아래와 같이하면 된다.

public interface MemberRepository extends JpaRepository<Member, Long> {
    @Query("select m.username from Member m")
    List<String> findUsernameList();
}

테스트해보자.

@Test
void findUsernameList(){
    Member member1 = new Member("member1", 10, null);
    Member member2 = new Member("member2", 10, null);
    Member member3 = new Member("member3", 10, null);

    memberRepository.save(member1);
    memberRepository.save(member2);
    memberRepository.save(member3);

    List<String> usernameList = memberRepository.findUsernameList();
    for (String username : usernameList) System.out.println(username);
}


실행결과:

member1
member2
member3

 


바로 DTO로 조회

 

이번에는 바로 DTO로 조회하는 법을 알아보자. 먼저 MemberDto는 아래와 같다.

@Data
public class MemberDto {
    private Long id;
    private String username;
    private String teamName;

    public MemberDto(Long id, String username, String teamName) {
        this.id = id;
        this.username = username;
        this.teamName = teamName;
    }
}

 

리퍼지토리는 아래와 같이 작성하면 된다.

public interface MemberRepository extends JpaRepository<Member, Long> {
    //DTO로 조회하기
    @Query("select new study.datajpa.entity.dto.MemberDto(m.id, m.username, t.name) from Member m join m.team t")
    List<MemberDto> findMemberDto();
}

(패키지 경로를 모두 명시해주어야 한다.)

(현재 페키지 경로)

 

이를 테스트해보면 아래와 같다.

@Test
void findMemberDto(){
    Team teamA = new Team("teamA");
    Team teamB = new Team("teamB");

    new Member("member1", 10, teamA);
    new Member("member2", 10, teamA);
    new Member("member3", 10, teamB);

    teamRepository.save(teamA);// cascade로 member들도 persist된다.
    teamRepository.save(teamB);

    List<MemberDto> memberDtoList = memberRepository.findMemberDto();
    for (MemberDto memberDto : memberDtoList) System.out.println(memberDto);
}



실행결과:

MemberDto(id=2, username=member1, teamName=teamA)
MemberDto(id=3, username=member2, teamName=teamA)
MemberDto(id=5, username=member3, teamName=teamB)

바로 엔티티로 조회된 것을 확인할 수 있다.

 


 

마지막으로 파라미터 바인딩(위치 기반)에 대해 조금 더 자세하게 알아보자.

 

기본적인 파라미터 바인딩:

(이미 이전에 우리가 살펴본 내용이다.)

 

 

위와 같은 기본적인 파라미터 바인딩 외에도 컨렉션으로 파라미터 바인딩을 하여 쿼리에 in을 사용할 수 있다.

컬렉션 파라미터 바인딩:

public interface MemberRepository extends JpaRepository<Member, Long> {
	//아래처럼 컬렉션을 사용하여 in절의 파라미터로 넣을 수 있다.
    @Query("select m from Member m where m.username in :names")
    List<Member> findByNames(@Param("names") Collection<String> names);
}

이를 테스트해보자.

@Test
void findByNames(){
    Member member1 = new Member("member1", 10, null);
    Member member2 = new Member("member2", 10, null);
    Member member3 = new Member("member3", 10, null);

    memberRepository.save(member1);
    memberRepository.save(member2);
    memberRepository.save(member3);

    List<Member> members = memberRepository.findByNames(Arrays.asList("member1", "member2"));
    for (Member member : members) System.out.println(member);
}



실행결과:

Member(id=1, username=member1, age=10)
Member(id=2, username=member2, age=10)

 

 

 

 

 

 

김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.