TIL

쿼리 메소드 기능 1

쿼리 메소드 기능 3가지

메소드 이름으로 쿼리 생성

스프링 데이터 JPA는 메소드 이름을 분석해서 JPQL 생성

이름과 나이를 기준으로 회원을 조회하려면?

순수 JPA

public List<Member> findByUsernameAndAgeGreaterThan(String username, int age) {
 return em.createQuery("select m from Member m where m.username = :username and m.age > :age")
			 .setParameter("username", username)
			 .setParameter("age", age)
			 .getResultList();
}

스프링 데이터 JPA

public interface MemberRepository extends JpaRepository<Member, Long> { 
    List<Member> findByUsernameAndAgeGreaterThan(String username, int age);
}

쿼리 메소드 필터 조건

스프링 데이터 JPA가 제공하는 쿼리 메소드 기능

참고: 이 기능은 엔티티의 필드명이 변경되면 인터페이스에 정의한 메서드 이름도 꼭 함께 변경해야 한다. 그렇지 않으면 애플리케이션을 시작하는 시점에 오류가 발생한다. 이렇게 애플리케이션 로딩 시점에 오류를 인지할 수 있는 것이 스프링 데이터 JPA의 매우 큰 장점이다.

단점

필터링 조건 등이 많아지면 메소드 이름이 너무 길어진다. 그래서 파라미터가 2개까지는 괜찮은데 3개부터는 다른 방법을 이용할 수도?

JPA NakmedQuery

JPA의 NamedQuery를 호출할 수 있음

@Entity
@NamedQuery(name="Member.findByUsername",
						 query="select m from Member m where m.username = :username")
public class Member {
 ...
}
List<Member> resultList = em.createNamedQuery("Member.findByUsername", Member.class)
			.setParameter("username", username)
			.getResultList();

스프링 데이터 JPA로 Named 쿼리 호출

public interface MemberRepository extends JpaRepository<Member, Long> { 
//** 여기 선언한 Member 도메인 클래스

		List<Member> findByUsername(@Param("username") String username);
}

실무에서 NamedQuery 사용할 일이 없다고 함!!

대신 @Query를 사용해서 리파지토리 메소드에 쿼리를 직접 정의한다.

@Query, 리포지토리 메소드에 쿼리 정의하기

메서드에 JPQL 쿼리 작성

public interface MemberRepository extends JpaRepository<Member, Long> {

		@Query("select m from Member m where m.username= :username and m.age = :age")
		List<Member> findUser(@Param("username") String username, @Param("age") int age);
}

참고: 실무에서는 메소드 이름으로 쿼리 생성 기능은 파라미터가 증가하면 메서드 이름이 매우 지저분해진다. 따라서 @Query 기능을 자주 사용하게 된다.

@Query, 값, DTO 조회하기

단순히 값 하나를 조회

@Query("select m.username from Member m")
List<String> findUsernameList();

DTO로 직접 조회

@Query("select new study.datajpa.dto.MemberDto(m.id, m.username, t.name) " +
			 "from Member m join m.team t")
List<MemberDto> findMemberDto();
@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;
	}
}

파라미터 바인딩

select m from Member m where m.username = ?0 //위치 기반
select m from Member m where m.username = :name //이름 기반

파라미터 바인딩

import org.springframework.data.repository.query.Param

public interface MemberRepository extends JpaRepository<Member, Long> {

		@Query("select m from Member m where m.username = :name")
		Member findMembers(@Param("name") String username);
}

컬렉션 파라미터 바인딩

@Query("select m from Member m where m.username in :names")
List<Member> findByNames(@Param("names") List<String> names);

반환 타입

List<Member> findByUsername(String name); //컬렉션
Member findByUsername(String name); //단건
Optional<Member> findByUsername(String name); //단건 Optional

조회 결과가 많거나 없으면?