JPQL(2)

9mond·2023년 10월 12일
0
post-thumbnail

1. JPQL 문법

  • select m from Member as m where m.age > 18
    -> Member : 엔티티 속성, 대소문자 구분(java 클래스는 대소문자를 구분하기 때문에), 엔티티 이름 사용, 테이블 이름이 아니다.
    @Entity(name = "mm") : 엔티티 이름을 mm으로 수정 시, jpql에서도 mm으로 써야한다.(하지만 실제 사용하진 않으니 이론적으로만 알고 있자.)
    -> JPQL 키워드 : select, from, where 대소문자 구분 안함.

1-1. 집합과 정렬

-	
select m
from Member m
	-> 전체를 다 가져오겠다.
    
-
select m
	count(m),	// 회원수
	sum(m.age),	// 나이 합
	avg(m.age),	// 평균 나이
	max(m.age),	// 최대 나이
	min(m.age)	// 최소 나이
from Member m

- group by, having

- order by

1-2. TypeQuery, Query

  • TypeQuery : 반환 타입이 명확할 때 사용
  • Query : 반환 타입이 명확하지 않을 때 사용
TypeQuery<Member> query = em.createQuery("select m from member m", Member.class);
	
Query query = em.createQuery("select m.username, m.age from Member m");

1-3. 결과 조회

  • query.getResultList() : 결과가 하나 이상일 때, 리스트 반환
    -> 결과가 없으면 빈 리스트 반환
    -> 빈 collection이 반환되기 때문에 NullPointException에 대한 걱정은 안해도 된다.

  • query.getSingleResult() : 결과가 정확히 하나(조심), 단일 객체 반환
    -> 결과가 없으면 : NoResultException
    -> 결과가 둘 이상이면 : NonUniqueResultException

1-4. 파라미터 바인딩

  • 이름 기준
	select m from Member m  where m.username = :username
	query.setParameter("username", usernameParam);	// 파라미터 바인딩
  • 위치 기준 - 쓰지 말것
	select m from Member m  where m.username = ?1
	query.setParameter(1, usernameParam);
	// 조건은 사라졌다가 생성 됐다가 하는데 어떻게 순서를 정하겠어

// 파라미터 바인딩
TypedQuery<Member> query = 
		em.createQuery("select m from Member m where m.username = :username", Member.class);
query.setParameter("username", "member1");
Member result = query.getSingleResult();
System.out.println("result : " + result.getUsername());

// 파라미터 바인딩 - 메세지 체인 방법(보통 이렇게 많이 사용)
Member result2 = 
	em.createQuery("select m from Member m where m.username = :username", Member.class)
	  .setParameter("username", "member1")
	  .getSingleResult();
System.out.println("result2 : " + result2.getUsername());

1-5. 프로젝션

  • select 절에 조회할 대상을 지정하는 것
  • 프로젝션 대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)
  • select m from Member m
    -> Member 엔티티 조회
  • select m.team from Member m
    -> Member와 관련된 team을 가지고 온다.
  • select m.address from Member m
    -> 임베디드 타입을 가지고 온다.
  • select m.username, m.age from Member m
    -> 스칼라 타입 프로젝트
List<Member> result	= em.createQuery("select m from Member m", Member.class).getResultList();

Member findmMember = result.get(0);
findmMember.setAge(20);

System.out.println("------------조인-------------");
// Member를 중심으로 Team을 가져온다 -> sql입장에선 join 밖에 방법이 없다.
// 그냥 join문을 날리는걸 더 권장한다.
/*
 * jpql 입장에서는 select문이 나가지만, 실제 sql입장에서는 member와 team을 join해서 결과를 찾아야한다.
 * 근데 join은 실제 sql문과 비슷하게 작성해야한다.
 */
List<Team> result2 = em.createQuery("select m.team from Member m", Team.class).getResultList();

// 코드상에 명시할 때 join을 했다는걸 알게 해주는게 좋다.
List<Team> result3 = 
		em.createQuery("select t from Member m join m.team t", Team.class).getResultList();

System.out.println("-----------임베디드--------------");
em.createQuery("select o.address from Order o", Address.class).getResultList();
// Order에 속한 address이기 때문에 이건 불가능하다. Address라는 엔티티가 없기 때문에
// em.createQuery("select o.address from Address o", Address.class).getResultList();

System.out.println("------------스칼라-------------");
// distinct : 중복제거 , 두번째 파라미터는 생략
em.createQuery("select distinct m.username, m.age from Member m").getResultList();

1-6. 여러 타입으로 조회

// 여러 타입으로 조회
// 1단계
List resultList = em.createQuery("select m.username, m.age from Member m").getResultList();
// 타입을 지정할 수 없기 때문에 Object로 받아온다.
Object o = resultList.get(0);
Object[] result = (Object[]) o;
System.out.println("username : " + result[0]);
System.out.println("age : " + result[1]);


// 2단계
List<Object[]> resultList2 = 
					em.createQuery("select m.username, m.age from Member m")
					  .getResultList();

Object[] result2 = resultList2.get(0);
System.out.println("username : " + result2[0]);
System.out.println("age : " + result2[1]);


// 3단계 - new 명령어로 조회, 제일 권장하는 방법
List<MemberDTO> result3 = 
		em.createQuery("select new com.codingbox.jpql.MemberDTO(m.username, m.age) from Member m")
          .getResultList();

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

1-7. 페이징 API

  • JPA는 페이지를 다음 두 API로 추상화
  • setFirstResult(int startPoint) : 조회 시작 위치(0부터 시작)
  • setMaxResults(int maxResult) : 조회할 데이터 수
    -> 몇 번째 부터 몇 건을 가지고 올래?
// 페이징 처리
String jpql = "select m from Member m order by m.age desc";
List<Member> resultList = em.createQuery(jpql, Member.class)
							.setFirstResult(10)
							.setMaxResults(20)
							.getResultList();

1-8. 조인

  • 문법이 객체 스타일로 나간다.
  • 내부 조인
	// inner 생략 가능
	-> select m from Member m inner join	m.team t
  • 외부 조인
	// outer 생략 가능. left outer join만 볼거다.
	-> select m from Member m left outer join m.team t

// 조인
String jpql = "select m from Member m inner join m.team t";
List<Member> resultList = em.createQuery(jpql, Member.class).getResultList();

String jpq2 = "select m from Member m inner join m.team t where t.name = :name";
List<Member> resultList2 = em.createQuery(jpql, Member.class).getResultList();

// left outer join
String jpql3 = "select t from Member m left outer join m.team t";
List<Member> resulList3 = em.createQuery(jpql3, Member.class).getResultList();

1-9. 서브쿼리

  • From 절의 서브쿼리는 현재 JPQL에서 불가능, 조인으로 풀 수 있으면 풀어서 해결
// 서브쿼리
String jpql = "select m from Member m where m.age" + " > (select avg(m2.age) from Member m2)";
List<Member> resultList = em.createQuery(jpql, Member.class).getResultList();

2. 설정파일

2-1. properries와 비교했을 때 y(a)ml의 장점

  • 한 눈에 보기에 좋다. 가독성이 좋다.
  • 불필요한 코드의 반복을 피할 수 있다.
  • 계층 구조로 이해하기 쉽고 쓰기가 편하다.
profile
개발자

0개의 댓글

관련 채용 정보