JPQL-1

OneTwoThree·2023년 7월 31일
0

출처


JPA는 다양한 쿼리 방법을 지원한다.

JPA를 사용하면 엔티티 객체를 중심으로 개발할 수 있다.

JPA는 SQL을 추상화한 JPQL이라는 객체지향 쿼리 언어 제공

            List<Member> result = em.createQuery(
                            "select m From Member m where m.username like  '%kim%'", Member.class)
                    		.getResultList();

SQL을 추상화했기 때문에 특정 DB SQL에 의존하지 않는다.
객체지향 SQL이다.

JPQL 기본 문법

JPQL은 특정 DB에 종속되지 않는다.

JPQL 기본 문법은 다음과 같다.

select m from Member as m where m.age>18

  • 엔티티와 속성은 대소문자를 구분함
  • JPQL 키워드는 대소문자를 구분하지 않음
  • 테이블 이름이 아닌 엔티티 이름을 사용한다
  • 별칭 m은 필수이고 as는 생략가능하다

집합과 정렬은 위와 같이 한다.


TypeQuery는 반환 타입이 명확할 때 사용하고 Query는 반환 타입이 명확하지 않을 때 사용한다

            TypedQuery<Member> typedQuery = em.createQuery("select m from Member m", Member.class);
            TypedQuery<String> typedQuery2 = em.createQuery("select m.username from Member m", String.class);
            Query query = em.createQuery("select m.username, m.age from Member m");

세번째의 경우 Typed를 사용할 수 없고 그냥 Query를 사용해야 한다. username과 age를 select해서 타입이 정의된 게 아니기 때문이다.
반환 타입이 명확하지 않을 때는 Query를 사용한다.


결과가 컬렉션일 때는 getResultList()를 사용한다.
결과가 없을 때는 빈 List를 반환한다.

            TypedQuery<Member> typedQuery = em.createQuery("select m from Member m", Member.class);
            List<Member> resultList = typedQuery.getResultList();
            for (Member member1 : resultList) {
                System.out.println("member1 = " + member1);
            }

결과가 무조건 하나일 때는 getSingleResult()를 사용한다.

            TypedQuery<Member> typedQuery = em.createQuery("select m from Member m", Member.class);
            Member singleResult = typedQuery.getSingleResult();
            System.out.println("singleResult = " + singleResult);

하지만 singleResult()를 호출했는데 결과가 안나오거나 여러개일 수 있다.

  • 결과가 없을 경우 : NoResultException
  • 결과가 하나일 경우 : NoUniqueResultException

위와 같이 파라미터 바인딩을 할 수 있다.
위치 기반은 사용하지 않는 게 좋다(중간에 하나 추가하면 다 수정해야 하기 때문에)

            Member singleResult = em.createQuery("select m from Member m where m.username = :username", Member.class)
                    .setParameter("username", "member1")
                    .getSingleResult();
            System.out.println("singleResult = " + singleResult);

보통은 이런 식으로 메소드 chaining으로 편리하게 사용한다.

프로젝션

Select 절에 조회할 대상을 지정하는 것을 프로젝션이라고 한다.
프로젝션 대상은 4가지 경우가 있다.
select m from Member m : 엔티티 프로젝션
select m.team from Member m : 엔티티 프로젝션
select m.address from Member m : 임베디드 타입 프로젝션
select m.username,m.age from Member m : 스칼라 타입 프로젝션

스칼라 타입 프로젝션

스칼라 타입 프로젝션 인 경우 값을 어떻게 가져와야 할까?
1. Query 타입으로 조회

            List resultList = em.createQuery("select m.username, m.age from Member m ")
                    .getResultList();

            Object o = resultList.get(0);
            Object[] result = (Object[]) o;
            System.out.println("username = "+result[0]);
            System.out.println("age = "+result[1]);

타입을 명기할 수 없어서 Obejct로 돌린다.

  1. Object[] 타입으로 조회
            List<Object[]> resultList = em.createQuery("select m.username, m.age from Member m ")
                    .getResultList();

            Object[] result = resultList.get(0);
            System.out.println("username = "+result[0]);
            System.out.println("age = "+result[1]);
  1. DTO로 조회
package jpashop;

public class MemberDTO {
    private String username;
    private int age;

    public MemberDTO(String username, int age) {
        this.username = username;
        this.age = age;
    }
}

위와 같이 값을 조회할 때 사용할 DTO를 만든다.

            List<MemberDTO> result = em.createQuery("select new jpashop.MemberDTO(m.username, m.age) from Member m", MemberDTO.class)
                    .getResultList();

            MemberDTO memberDTO = result.get(0);
            System.out.println("memberDTO.getUsername() = " + memberDTO.getUsername());
            System.out.println("memberDTO.getAge() = " + memberDTO.getAge());

selecct new jpashop.MemberDTO(m.usrname, m.age)와 같이 패키지명까지 입력해서 new로 DTO로 받을 수 있다.
패키지명이 길면 다 적어야 한다는 단점이 있지만 제일 깔끔한 방법이다.

페이징

JPA 페이징은 다음 두 API로 추상화되어있다.
setFirstResult(int startPosition)
setMaxResult(int maxResult)

            List<Member> result = em.createQuery("select m from Member m order by m.age desc", Member.class)
                    .setFirstResult(0)
                    .setMaxResults(10)
                    .getResultList();

            System.out.println("result.size() = " + result.size());
            for (Member member1 : result) {
                System.out.println("member1 = " + member1);
            }

DB 방언에 맞춰 알맞은 쿼리가 나간다.

0개의 댓글