@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를 바탕으로 정리하였습니다.
'JPA > 스프링 DATA JPA' 카테고리의 다른 글
Data JPA 07 벌크성 수정 쿼리 (0) | 2022.01.07 |
---|---|
Data JPA 06 쿼리 메서드 - 반환타입, 페이징 (0) | 2022.01.06 |
Data JPA 04 쿼리 메서드 - NamedQuery (0) | 2022.01.05 |
Data JPA 03 쿼리 메소드 - 메서드 이름으로 쿼리 생성 (0) | 2022.01.05 |
Data JPA 02 - 예제 도메인 확인하기, 공통 인터페이스 (0) | 2022.01.04 |