Post

JPA 정렬

1. JPA/JQL API를 사용한 정렬

JQL을 사용하여 정렬하려면 Order By 절을 사용한다.

1
2
String jql ="Select f from Foo as f order by f.id";
Query query = entityManager.createQuery (jql);

이 쿼리를 기반으로 JPA는 다음과 같은 간단한 SQL 문을 생성한다.

1
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ from Foo foo0_ order by foo0_.id

JQL 문자열의 SQL 키워드는 대소문자를 구분하지 않지만 엔터티 이름과 해당 속성은 대소문자를 구분한다.

1) 정렬 순서 설정

기본적으로 정렬 순서는 오름차순 이지만 JQL 문자열에서 명시적으로 설정할 수 있다. 순수 SQL에서와 마찬가지로 정렬 옵션은 asc 및 desc 이다.

1
2
String jql = "Select f from Foo as f order by f.id desc";
Query sortQuery = entityManager.createQuery(jql);

생성된 SQL 쿼리에는 주문 방향이 포함된다.

1
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ from Foo foo0_ order by foo0_.id desc

2) 두 개 이상의 속성으로 정렬

여러 속성을 기준으로 정렬하려면 JQL 문자열의 order by 절에 다음 속성을 추가한다.

1
2
String jql ="Select f from Foo as f order by f.name asc, f.id desc";
Query sortQuery = entityManager.createQuery(jql);

두 정렬 조건은 모두 생성된 SQL 쿼리 문에 나타난다.

1
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ from Foo foo0_ order by foo0_.name asc, foo0_.id desc

3) Null 값의 정렬 우선 순위 설정

null의 기본 우선순위는 데이터베이스에 따라 다르지만, HQL 쿼리 문자열의 NULLS FIRST 또는 NULLS LAST 절을 통해 사용자 정의할 수 있다.

다음은 간단한 예이다. Foo의 이름을 내림차순으로 정렬하고 끝에 Null을 배치한다.

1
2
Query sortQuery = entityManager.createQuery
    ("Select f from Foo as f order by f.name desc NULLS LAST");

생성된 SQL 쿼리에는 is null, 1 else 0 end 절 (3번째 줄)이 포함된다.

1
2
3
Hibernate: select foo0_.id as id1_4_, foo0_.BAR_ID as BAR_ID2_4_, 
    foo0_.bar_Id as bar_Id2_4_, foo0_.name as name3_4_,from Foo foo0_ order 
    by case when foo0_.name is null then 1 else 0 end, foo0_.name desc

4) 일대다 관계 정렬

일대다 관계의 엔터티를 정렬 하는 예이다. Bar에는 Foo 엔터티 컬렉션이 들어 있다.

Bar 엔티티와 Foo 엔티티 컬렉션을 정렬한다. JPA는 이 작업에 특히 간단하다.

  • 컬렉션 정렬: Bar 엔터티의 Foo 컬렉션 앞에 OrderBy 주석을 추가한다.
1
2
@OrderBy("name ASC")
List <Foo> fooList;
  • 컬렉션을 포함하는 엔터티 정렬:
1
2
3
String jql = "Select b from Bar as b order by b.id";
Query barQuery = entityManager.createQuery(jql);
List<Bar> barList = barQuery.getResultList();

@OrderBy 주석은 선택 사항이지만, 이 경우에는 각 Bar의 Foo 컬렉션을 정렬하려고 하기 때문에 이를 사용한다.

RDMS에 전송된 SQL 쿼리이다.

1
2
3
4
5
6
7
8
Hibernate: select bar0_.id as id1_0_, bar0_.name as name2_0_ from Bar bar0_ order by bar0_.id

Hibernate: 
select foolist0_.BAR_ID as BAR_ID2_0_0_, foolist0_.id as id1_4_0_, 
foolist0_.id as id1_4_1_, foolist0_.BAR_ID as BAR_ID2_4_1_, 
foolist0_.bar_Id as bar_Id2_4_1_, foolist0_.name as name3_4_1_ 
from Foo foolist0_ 
where foolist0_.BAR_ID=? order by foolist0_.name asc

첫 번째 쿼리는 부모 Bar 엔터티를 정렬한다. 두 번째 쿼리는 Bar에 속하는 자식 Foo 엔터티 컬렉션을 정렬하기 위해 생성된다.

2. JPA Criteria Query Object API를 사용한 정렬

JPA Criteria를 사용하면 orderBy 메서드는 모든 정렬 매개변수를 설정하는 “원스톱” 대안이다. 정렬 방향과 정렬 기준 속성을 모두 설정할 수 있다. 다음은 메서드의 API이다.

  • orderBy (CriteriaBuilder.asc): 오름차순으로 정렬한다.

  • orderBy (CriteriaBuilder.desc): 내림차순으로 정렬한다.

각 Order 인스턴스는 asc 또는 desc 메서드를 통해 CriteriaBuilder 객체로 생성된다.

다음은 간단한 예이다. Foos를 이름순으로 정렬한다.

1
2
3
4
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class);
CriteriaQuery<Foo> select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")));

get 메서드의 인수는 속성 이름과 일치해야 하므로 대소문자를 구분한다.

간단한 JQL과 달리 JPA Criteria Query Object API는 쿼리에서 명시적인 순서 방향을 강제로 지정한다. 이 코드 조각의 마지막 줄에서 criteriaBuilder 객체가 asc 메서드를 호출하여 정렬 순서를 오름차순으로 지정한다.

위의 코드를 실행하면 JPA는 아래에 표시된 SQL 쿼리를 생성한다. JPA Criteria Object는 명시적 asc 절이 있는 SQL 문을 생성한다.

1
2
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
    from Foo foo0_ order by foo0_.name asc

1) 두 개 이상의 속성으로 정렬

여러 개의 속성을 기준으로 정렬하려면 정렬할 각 속성에 대한 Order 인스턴스를 orderBy 메서드에 전달하기만 하면 된다.

다음은 이름과 ID를 각각 오름차순과 내림차순으로 정렬하는 간단한 이다.

1
2
3
4
5
CriteriaQuery<Foo> criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root<Foo> from = criteriaQuery.from(Foo.class); 
CriteriaQuery<Foo> select = criteriaQuery.select(from); 
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")),
    criteriaBuilder.desc(from.get("id")));

해당 SQL 쿼리는 아래와 같다.

1
2
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_ 
    from Foo foo0_ order by foo0_.name asc, foo0_.id desc

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.