2016-09-12 4 views
0

주문하고자하는 테이블 열이 있습니다. 문제는 열 값에 숫자와 텍스트가 모두 포함되어 있다는 것입니다. 예를 들어 결과가 다음과 같이 정렬됩니다. 나는이 작업을 수행 할 수있는 옵션을 찾을 수 없습니다 Spring 설정을 볼 때스프링 데이터로 자연 정렬을 사용하는 방법 Jpa

1. group one 
10. group ten 
11. group eleven 
2. group two 

하지만 결과를 싶습니다이

1. group one 
2. group two 
10. group ten 
11. group eleven 

처럼 자연스럽게 주문할 수 있습니다. Spring Pageable 클래스를 사용하여 JPA 스펙을 추가로 사용하여 주문 필드와 방향을 설정합니다. 메서드 자체는 기본적으로 처음 20 개의 결과가있는 Page를 반환합니다.

오라클이 자연스러운 주문을 지원하지 않는다고해서 저장 프로 시저가 있습니다. 이 프로 시저를 사용하여 조회를 실행하면 원하는 결과를 얻을 수 있습니다.

select ... from group order by NATURALSORT(group.name) asc 

예상대로 텍스트가 포함 된 모든 주문 된 열을 중심으로이 절차를 사용하고 싶습니다. 페이지/페이지 및 사양을 유지 관리하는 동안 내가 이런 짓 연구는 지금까지

  • 중 하나를 생성하고 사용자 정의 사양
  • 을 구현 또는 정렬 객체가 변형되는 방식을 변경하기 위해 SimpleJpaRepository을 확장 포함 할 수있는 솔루션에 저를 지적한다.

하지만 원시 SQL을 사용하여 주문을 설정할 수있는 방법을 찾지 못했습니다. 주문을 설정하는 유일한 방법은 orderBy을 호출하고 Order 개체를 포함하는 것입니다.

일반적으로 여전히 사용할 수있는 동안 내 저장 프로 시저와 함께 하나의 order by column을 포장 할 수있는 방법

  1. 최대 절전 모드, 봄 데이터 JPA를 사용할 때 자연 순서를 전체적으로 사용하는 방법 및 Oracle 데이터베이스
  2. 그렇지 않은 경우가 있는가, Page findAll(Pageable, Specifications) 방법?

미리 감사드립니다.

답변

0

Spring JPA와 Hibernate의 소스 코드를 파고 들자 나는 내 문제에 대한 해결책을 찾을 수 있었다. 나는 이것이 이것을 해결하는 좋은 방법이 아니라고 확신하지만, 내가 찾을 수있는 유일한 방법이다.

SingularAttributePath 클래스를 확장하여 쿼리 순서 부분에 대한 래퍼를 구현했습니다. 이 클래스에는 실제 쿼리에 삽입되는 문자열을 생성하는 render 메서드가 있습니다. 내 구현은 다음과 같습니다.

@Override 
public String render(RenderingContext renderingContext) { 
    String render = super.render(renderingContext); 
    render = "MYPACKAGE.NSORT(" + render + ")"; 
    return render; 
} 

다음으로 SimpleJpaRepository 클래스의 주문 변환 기능을 확장했습니다. 기본적으로이 작업은 QueryUtils.toOrders(sort, root, builder)을 호출하여 수행됩니다.그러나 메서드를 호출하는 것이 불가능하기 때문에 재정의하는 것이 불가능하므로 결국 toOrder 메서드를 호출하고 결과를 원하는대로 변경했습니다.

이것은 결과의 모든 주문을 SingularAttributePath 클래스의 맞춤 구현으로 바꾸는 것을 의미합니다. 추가로 나는 클래스에 의해 사용되는 클래스 인 Sort을 래핑 된 것과 그렇지 않은 것 (NaturalOrder라고 불리는 것)을 제어 할 수 있도록 확장했다. 하지만 잠시 후에 그걸 보겠습니다. 내 구현은 query.orderBy(resultlist)를 호출하여 (일부 검사는 탈락된다)

// Call the original method to convert the orders 
List<Order> orders = QueryUtils.toOrders(sort, root, builder); 
for (Order order : orders) { 
    // Fetch the original order object from the sort for comparing 
    SingularAttributePath orderExpression = (SingularAttributePath) order.getExpression(); 
    Sort.Order originalOrder = sort.getOrderFor(orderExpression.getAttribute().getName()); 
    // Check if the original order object is instantiated from my custom order class 
    // Also check if the the order should be natural 
    if (originalOrder instanceof NaturalSort.NaturalOrderm && ((NaturalSort.NaturalOrder) originalOrder).isNatural()){ 
    // replace the order with the custom class 
    Order newOrder = new OrderImpl(new NaturalSingularAttributePathImpl(builder, expression.getJavaType(), expression.getPathSource(), expression.getAttribute())); 
    resultList.add(newOrder); 
    }else{ 
    resultList.add(order); 
    } 
} 
return resultList; 

다음 쿼리에 추가됩니다 반환 목록이 가까이 보인다. 백엔드 용입니다.

랩핑 조건을 제어하기 위해 에 사용 된 Sort 클래스를 확장했습니다 (몇 줄을 뒤에서 언급 했음). 추가하고자하는 유일한 기능은 방향 열거 형에 4 가지 유형이 있다는 것입니다.

  • ASC (기본 오름차순)
  • DESC (기본 내림차순)
  • NASC (정상 오름차순)
  • NDESC (정상 내림차순)

마지막 두 값 만 자리로서 작용한다. 조건에 사용되는 isNatural 부울 (확장 된 Order 클래스의 변수)을 설정합니다. 쿼리가 변환 될 때 기본 변형으로 다시 매핑됩니다.

public Direction getNativeDirection() { 
    if (this == NaturalDirection.NASC) 
    return Direction.ASC; 
    if (this == NaturalDirection.NDESC) 
    return Direction.DESC; 
    return Direction.fromString(String.valueOf(this)); 
} 

는 마지막으로 나는 PageableHandlerMethodArgumentResolver에 의해 사용되는 SortHandlerMethodArgumentResolver를 교체했다. 이 유일한 작업은 내 NaturalSort 클래스의 인스턴스를 만들고 기본값 Sort 클래스 대신 Pageable 객체에 전달하는 것입니다.

결과적으로 결과가 정렬되는 동안 동일한 REST 끝점을 호출 할 수 있습니다.

Default Sorting 
/api/v1/items?page=0&size=20&sort=name,asc 
Natural Sorting 
/api/v1/items?page=0&size=20&sort=name,nasc 

이 솔루션은 자연 분류 및 JPA와 관련하여 동일하거나 유사한 문제가있는 사용자에게 도움이되기를 바랍니다. 질문이나 개선 사항이 있으면 알려주십시오.

1

나는 그런 특징을 알지 못합니다. 그러나 별도의 열에 숫자를 저장 한 다음 해당 열을 기준으로 정렬하면 추가적인 이점으로 더 우수한 정렬 성능을 얻을 수 있습니다.

+0

이름은 사용자가 설정하므로 실제로는 옵션이 아닙니다. 그래서 저는 그 정보의 내용에 아무런 영향을 미치지 않습니다. –

+0

findAll 메서드에서 생성 된 쿼리에 원시 SQL을 추가하는 방법이 있습니까? –

+0

@RobinHermans 그래서, 미리 정의 된 형식의 입력 된 텍스트가 있습니까? 의미, 그 사용자가 입력 할 수 있습니다 _ "이것은 두 번째 그룹입니다"_ 와야합니다 _ "이것은 열 번째 그룹입니다"_ 정렬 순서에? –