val result = em.createQuery("select m from Member as m where m.username like '%kim%'", Member::class.java).resultList
// Criteria 사용 준비
val cb: CriteriaBuilder = em.criteriaBuilder
val query: CriteriaQuery<Member> = cb.createQuery(Member::class.java)
// 루트 클래스 (조회를 시작할 클래스)
val m: Root<Member> = query.from(Member::class.java)
// 쿼리 생성
val cq: CriteriaQuery<Member> = query.select(m).where(cb.equal(m.get<String>("username"), "kim"))
// 결과
val result = em.createQuery(cq).resultList
ex) select m from Member as m where m.age > 20
엔티티와 속성은 대소문자 구분 해야함
-> Member , age
JPQL 키워드는 대소문자 구분 할 필요 없음
-> select, from, where
테이블 이름이 아닌 엔티티 이름 사용 -> Member
별칭은 필수 -> m
-> as 키워드는 생략 가능
기본적으로 제공하는 문법은 사용 가능
select, from, where, groupby, having, orderby
count, sum, avg, max, min
val typedQuery: TypedQuery<Member> = em.createQuery("select m from Member m", Member::class.java)
val query: Query = em.createQuery("select m.username, m.age from Member m")
getResultList() : 결과가 하나 이상일 때 리스트를 반환
-> 결과가 없으면 빈 리스트
getSingleResult() : 결과가 정확히 하나일 때 단일 객체 반환
-> 결과가 없거나 2개 이상일 경우 예외 발생
// 하나 이상의 결과
val resultList = query.resultList
// 하나 결과
query.singleResult
val q: TypedQuery<Member> = em.createQuery("select m from Member m where m.username = :username", Member::class.java)
q.setParameter("username", "member1")
val q = em.createQuery("select m from Member m where m.username = ?1", Member::class.java)
q.setParameter(1, "member1")
엔티티 프로젝션
-> em.createQuery("select m from Member m", Member::class.java)
-> em.createQuery("select m.team from Member m", Team::class.java)
임베디드 타입 프로젝션
-> Address 는 임베디드 타입
-> em.createQuery("select o.address from Order o", Order::class.java)
스칼라 타입 프록젝션
-> em.createQuery("select m.username, m.age from Member m")
setFirstResult(startPosition: Int) : 조회 시작 위치
setMaxResults(maxResult: Int) : 조회할 데이터 수
val result = em.createQuery("select m from Member m order by m.age desc ", Member::class.java)
.setFirstResult(1)
.setMaxResults(10)
.resultList
내부 조인 : select m from Member m [INNER] join m.team t
외부 조인 : select m from Member m left [OUTER] join m.team t
세타 조인 : select count(m) from Member m Team t where m.username = t.name
ex) 나이가 평균보다 많은 회원
-> select m from Member m where m.age (select avg(m2.age) from Member m2)
[NOT] Exists (subquery) : 서브쿼리에 결과가 존재하면 참
-> em.createQuery("select m from Member m where exists (select t from m.team t where t.name = 'teamA')")
{ALL | ANY | SOME } (subquery)
-> ALL : 모두 만족하면 참
-> ANY, SOME : 조건을 하나라도 만족하면 참
[NOT] IN (subquery) : 서브쿼리의 결과 중 하나라도 같은 것이 있으면 참
JPA는 WHERE, HAVING 절에서만 서브 쿼리 사용 가능
-> 하이버네이트에서는 SELECT 절도 가능
FROM 절의 서브 쿼리는 JPQL에서 불가능
-> 조인으로 풀 수 있으면 풀어서 해결
문자 : ‘HELLO’, ‘She’’s’
숫자: 10L(Long), 10D(Double), 10F(Float)
Boolean: TRUE, FALSE
ENUM: xxx.Type.Admin (패키지명 포함)
-> em.createQuery("select m from Member m where m.type = xxx.Type.Admin")
엔티티 타입: TYPE(m) = Member (상속 관계에서 사용)
SQL과 문법이 같은 식
em.createQuery(
"select " +
"case when m.age <= 10 then '학생요금'" +
"when m.age >= 60 then '경로요금'" +
"else '일반요금'" +
"end " +
"from Member m"
)
em.createQuery(
"select " +
"case t.name " +
"when '팀A' then '인센티브110%'" +
"when '팀B' then '인센티브120%'" +
"else '인센티브105%'" +
"end " +
"from Team t"
)
em.createQuery("select coalesce(m.username, '이름 없는 회원') from Member m ")
em.createQuery("select nullif(m.username, '관리자') from Member m ")
CONCAT
SUBSTRING
TRIM
LOWER, UPPER
LENGTH
LOCATE
ABS, SQRT, MOD
SIZE, INDEX(JPA 용도)
사용자 정의 함수 호출
-> 하이버네이트는 사용 전 방언에 추가해야 함
-> 사용하는 DB 방언을 상속받고, 사용자 정의 함수를 등록
-> 커스텀한 DB 방언 등록 (persistence.xml)
class MyH2Dialect() : H2Dialect() {
override fun registerFunction(name: String?, function: SQLFunction?) {
super.registerFunction("group_concat", StandardSQLFunction("group_concat", StandardBasicTypes.STRING))
super.registerFunction(name, function)
}
}
// main.kt
val result = em.createQuery("select function('group_concat', m.username) from Member m ", String::class.java).resultList