-
#JPA-18 JPQL(Java Persistence Query Language)JPA 2021. 2. 23. 16:07
[출처] 인프런 김영한 강사님 -자바 ORM 표준 JPA 프로그래밍 기본
JPQL(Java Persistence Query Language)
(JPQL - 기본 문법과 기능)
JPQL 소개
• JPQL은 객체지향 쿼리 언어다.따라서 테이블을 대상으로 쿼리 하는 것이 아니라 엔티티 객체를 대상으로 쿼리한다.
• JPQL은 SQL을 추상화해서 특정데이터베이스 SQL에 의존하 지 않는다.
• JPQL은 결국 SQL로 변환된다.
Member Class Entity
package jpql; import javax.persistence.*; @Entity public class Member { @Id @GeneratedValue private Long id; private String username; private int age; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Team Class Entity
package jpql; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import java.util.ArrayList; import java.util.List; @Entity public class Team { @Id @GeneratedValue private Long id; private String name; @OneToMany(mappedBy = "team") private List<Member> members = new ArrayList<>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
Order Class Entity
package jpql; import javax.persistence.*; @Entity @Table(name = "ORDERS") public class Order { @Id @GeneratedValue private Long id; private int orderAmount; @Embedded private Address address; @ManyToOne @JoinColumn(name ="PRODUCT_ID") private Product product; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public int getOrderAmount() { return orderAmount; } public void setOrderAmount(int orderAmount) { this.orderAmount = orderAmount; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } }
Product Class Entity
package jpql; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.OneToMany; import java.util.ArrayList; import java.util.List; @Entity public class Product { @Id @GeneratedValue private Long id; private String name; private int price; private int stockAmount; @OneToMany(mappedBy = "product") private List<Order> orders = new ArrayList<>(); public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } public int getStockAmount() { return stockAmount; } public void setStockAmount(int stockAmount) { this.stockAmount = stockAmount; } }
Address Class embedd
package jpql; import javax.persistence.Embeddable; @Embeddable public class Address { private String city; private String street; private String zipcode; public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getStreet() { return street; } public void setStreet(String street) { this.street = street; } public String getZipcode() { return zipcode; } public void setZipcode(String zipcode) { this.zipcode = zipcode; } }
JPQL 문법
• select m from Member as m where m.age > 18
• 엔티티와 속성은 대소문자 구분O (Member, age) 가지고 있는 property랑 똑같이 써야한다.
• JPQL 키워드는 대소문자 구분X (SELECT, FROM, where)
• 엔티티 이름 사용, 테이블 이름이 아님(Member)
<클래스 이름이 같을 경우는 어떻게 하나요? ->클래스 이름을 걍바꿔>
• 별칭은 필수(m) (as는 생략가능)
집합과 정렬
• GROUP BY, HAVING
• ORDER BY
TypeQuery, Query
• TypeQuery: 반환 타입이 명확할 때 사용
• Query: 반환 타입이 명확하지 않을 때 사용
결과 조회 API
• query.getResultList(): 결과가 하나 이상일 때, 리스트 반환
• 결과가 없으면 빈 리스트 반환
• query.getSingleResult(): 결과가 정확히 하나, 단일 객체 반환
• 결과가 없으면: javax.persistence.NoResultException
• 둘 이상이면: javax.persistence.NonUniqueResultException
• 얘는 특별하게 exception을 반환하기때문에 try catch를 해줘야한다. ㅠㅠ
파라미터 바인딩 - 이름 기준, 위치 기준
이름기준
보통은 메서드 체인을 하여 이런식으로 쓴다.
위치기준 (웬만하면 쓰지마라 1,2,3인데 중간에 뭐 끼워넣으면 장애가 발생한다.)
프로젝션
• SELECT 절에 조회할 대상을 지정하는 것
• 프로젝션 대상: 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자등 기본 데이터 타 입)
• SELECT m FROM Member m -> 엔티티 프로젝션 (m이 Member Entity의 alias)
• SELECT m.team FROM Member m -> 엔티티 프로젝션
• SELECT m.address FROM Member m -> 임베디드 타입 프로젝션
임베디드 타입만으로는 안되고 그것의 Entity로 부터 시작해야한다.
• SELECT m.username, m.age FROM Member m -> 스칼라 타입 프로젝션
• DISTINCT로 중복 제거
프로젝션 - 여러 값 조회
• SELECT m.username, m.age FROM Member m
• 1. Query 타입으로 조회
• 2. Object[] 타입으로 조회
Hibernate: /* select o.address from Order o */ select order0_.city as col_0_0_, order0_.street as col_0_1_, order0_.zipcode as col_0_2_ from ORDERS order0_
• 3. new 명령어로 조회 (제일 깔끔한 것!!)
• 단순 값을 DTO로 바로 조회 SELECT new jpabook.jpql.UserDTO(m.username, m.age) FROM Member m
MemberDTO Class
package jpql; public class MemberDTO { private String username; private int age; public MemberDTO(String username, int age) { this.username = username; this.age = age; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
만약 entity로 가져오면 상관없는데 위처럼 entity가 아닌 경우는 new 로 DTO를 만들어서 사용.
• 패키지 명을 포함한 전체 클래스 명 입력
• 순서와 타입이 일치하는 생성자 필요
'JPA' 카테고리의 다른 글
#JPA-20 JPQL- 경로 표현식 (0) 2021.02.23 #JPA-19 페이징 API, JOIN, JPA 기타 (0) 2021.02.23 #JPA-17 JPA가 지원하는 다양한 쿼리 방법 (0) 2021.02.23 #JPA-16 값 타입 (0) 2021.02.22 #JPA-15 속성 전이: CASCADE (0) 2021.02.19