41. 객체지향 쿼리 언어(8)

41. 객체지향 쿼리 언어(8)

2. JPQL

11. 다형성 쿼리

JPQL로 부모 엔티티를 조회하면 그 자식 엔티티도 함께 조회한다. 아래 예제를 보면 Item의 자식으로 Book, Album, Movie가 있다.

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {...}

@Entity
@DiscriminatorValue("B")
public class Book extends Item {
    ...
    private String author;
}

// Album, Movie 생략

다음과 같이 조회하면 Item의 자식도 같이 조회한다.

List resultList = em.createQuery("select i from Item i").getResultList();

단일 테이블 전략(InheritanceType.SINGLE_TABLE)을 사용할 때 실행되는 SQL은 다음과 같다.

// SQL
SELECT * FROM ITEM

조인 전략(InheritanceType.JOINED)을 사용할 때 실행되는 SQL은 다음과 같다.

// SQL
SELECT
    i.ITEM_ID, i.DTYPE, i.name, i.price, i.stockQuantity,
    b.author, b.isbn,
    a.artist, a.etc,
    m.actor, m.director
FROM
    Item i
left outer join
    Book b on i.ITEM_ID=b.ITEM_ID
left outer join
    Album a on i.ITEM_ID=a.ITEM_ID
left outer join
    Movie m on i.ITEM_ID=m.ITEM_ID

TYPE

TYPE은 엔티티의 상속 구조에서 조회 대상을 특정 자식 타입으로 한정할 때 주로 사용한다.

예시) Item 중에 Book, Movie를 조회하라.

// JPQL
select i from Item i
where type(i) IN (Book, Movie)

// SQL
SELECT i FROM Item i
WHERE i.DTYPE in ('B', 'M')

TREAT(JPA 2.1)

TREAT는 JPA 2.1에 추가된 기능인데 자바의 타입 캐스팅과 비슷하다. 상속 구조에서 부모 타입을 특정 자식 타입으로 다룰 때 사용한다. JPA 표준은 FROM, WHERE 절에서 사용할 수 있지만 하이버네이트는 SELECT 절에서도 TREAT를 사용할 수 있다.

예시) 부모인 Item과 자식 Book이 있다.

// JPQL
select i from Item i where treat(i as Book).author = 'kim'

// SQL
select i.* from Item i
where
    i.DTYPE='B'
    and i.author='kim'

JPQL을 보면 treat를 사용해서 부모 타입인 Item을 자식 타입인 Book으로 다룬다. 따라서 author 필드에 접근할 수 있다.

12. 사용자 정의 함수 호출(JPA 2.1)

JPA 2.1부터 사용자 정의 함수를 지원한다.

문법 :

function_invocation::=FUNCTION(function_name {, function_args}*)

예시

select function('group_concat', i.name) from Item i

하이버네이트 구현체를 사용하면 아래 예제와 같이 방언 클래스를 상속해서 구현하고 사용할 데이터베이스 함수를 미리 등록해야 한다.

public class MyH2Dialect extends H2Dialect {

    public MyH2Dialect() {
        registerFunction("group_concat", new StandardSQLFunction
            ("group_concat", StandardBasicTypes.STRING));
    }
}

그리고 아래 예제와 같이 hibernate.dialect에 해당 방언을 등록해야 한다.

  • persistence.xml
<property name="hibernate.dialect" value="hello.MyH2Dialect" />

하이버네이트 구현체를 사용하면 다음과 같이 축약해서 사용할 수 있다.

select group_concat(i.name) from Item i

13. 기타 정리

  • enum은 = 비교 연산만 지원한다.
  • 임베디드 타입은 비교를 지원하지 않는다.

EMPTY STRING

JPA 표준은 ''을 길이 0인 Empty String으로 정했지만 데이터베이스에 따라 ''를 NULL로 사용하는 데이터베이스도 있으므로 확인하고 사용해야 한다.

NULL 정의

  • 조건을 만족하는 데이터가 하나도 없으면 NULL이다.
  • NULL은 알 수 없는 값(unknown value)이다. NULL과의 모든 수학적 계산 결과는 NULL이 된다.
  • Null == Null은 알 수 없는 값이다.
  • Null is Null은 참이다.

JPA 표준 명세는 NULL(U) 값과 TRUE(T), FALSE(F)과의 논리 계산을 다음과 같이 정의했다.

아래 표는 AND 연산을 정리했다.

AND T F U
T T F U
F F F F
U U F U

아래 표는 OR 연산을 정리했다.

OR T F U
T T T T
F T F U
U T U U

아래 표는 NOT 연산을 정리했다.

NOT
T F
F T
U U

참고

  • 자바 ORM 표준 JPA 프로그래밍

좋은 웹페이지 즐겨찾기