
JPA는 entity 객체를 중심으로 이루어진다.
하지만, 모든 DB 데이터를 객체로 변환해서 검색하는 것은 불가능하다.
그래서 JPA는 객체지향 쿼리 언어인 JPQL을 제공하기 때문에 SQL과 비슷한 형태의 쿼리를 작성하여 조회를 할 수 있다.
→ JPQL은 엔티티 객체를 대상으로 쿼리를 질의하고, SQL은 DB 테이블을 대상으로 쿼리를 질의한다.
1. @Query
public interface UserRepository extends JpaRepository<User, String> {
@Query(value = "select user " +
"from User user " +
"where user.name = :name")
List<User> findByName(@Param("name") String name);
public interface UserRepository extends JpaRepository<UserEntity, Long> {
@Query(
value = "select * from user as u where u.name = :name",
nativeQuery = true
)
List<UserEntity> score(
@Param (value="name") String name
);
}
2. EntityManager.createQuery
em.createQuery(“select m from Member m where m.username like ~ ”)
TypeQuery<Member> query = em.createQuery(“select m from Member m”, Member.class)
List resultlist = query.getResultList();
결과가 없으면 빈 컬렉션을 반환한다.
Member result = query.getSingleResult();
무조건 하나의 값이 반환되어야 한다.
만약 값이 없다면 noResultException, 값이 두개 이상이라면 notUniqueException 에러가 발생한다.
TypeQuery<Member> query = em.createQuery(“select m from Member m where m.username = :username”, Member.class)
query.setParameter(“username,”member1”)
.getSingleResult(); //체이닝
JPQL의 SELECT절을 이용하여 어떤 데이터를 조회할 것인지 정의하는 것
1. Entity 프로젝션
→ 객체 또는 객체의 속성 조회
//객체 조회
em.createQuery(“select m from Member m", Member.class);
//객체의 속성 조회 > Team은 Entity이다.
em.createQuery(“select m.team from Member m", Team.class);
2. Embedded 프로젝션
// 조회하는 데이터가 값 타입이다. (=Typed Query)
em.createQuery(“select m.address from Member m", Address.class);
3. Scalar 프로젝션
→ 조회하는 데이터의 타입과 상관없이 여러 개를 가져오는 방법
em.createQuery("select p.name, p.address, p.team from Player p");
스칼라타입 프로젝션은 서로 다른 자료형을 가진 데이터를 조회하므로, Query를 사용한다.
Query형식은 조회 결과의 자료형을 정할 수 없으므로, Object 배열을 사용하여 받아온다.
그러나 이 방식은 코드가 깔끔하지 않아 선호되는 방식이 아니다.
3-1. DTO, new 키워드 사용
매번 데이터를 위한 DTO를 작성할 수는 없으니 자주 조회되는 경우에 DTO를 이용하자
@Getter
@Setter
@AllArgsConstructor
public class MemberDTO {
private String name;
private Address address;
private Team team;
}
//jpql
List<MemberDTO> resultList = em.createQuery("select new jpql.MemberDTO(m.name, m.address, m.team) from Member m", MemberDTO.class)
.getResultList();
JPA가 실행할 쿼리를 정확이 명시해주자.
예를 들어 위의 방식대로 join을 명시해주지 않아도 내부에서는 join 동작이 된다.
하지만 유지보수 측면에서 보면 위의 코드만으로는 내부 동작을 유추하기 어렵다.
아래와 같이 작성하는 것을 권장한다.
List<Team> resultList = em.createQuery("select t from Player p join p.team t", Team.class)
.getResultList();