2016-09-12 11 views
0

私は注文したいテーブルの列を持っています。問題は、列の値に数値とテキストの両方が含まれていることです。たとえば、結果は次のようになります。Springデータで自然なソートを使用する方法Jpa

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

しかし、私はSpring構成を見ると、私はあなたがこれを行うことを可能にするオプションを見つけることができないよう、この

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

のように、自然に注文する結果をしたいと思います。私はSpring Pageableクラスを使用して、注文フィールドと方向を設定し、JPA仕様を追加使用します。メソッド自体は、デフォルトで最初の20個の結果を持つPageを返します。

私はOracleがNaturalの注文をサポートしているとは思わないので、そのためのストアド・プロシージャがあります。このプロシージャを使用して問合せを実行すると、目的の結果が得られます。

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

あなたは私がテキストを含むすべての注文の列の周りにラップすることにより、その手順を使用したいのですが予想されるように。ページング/ページと仕様の使用を維持しながら。私はこれを行った研究はこれまで

  • どちらの作成とカスタム仕様
  • を実装するかSortオブジェクトが変換される方法を変更する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クラスのOrder変換機能を拡張しました。デフォルトでは、これはQueryUtils.toOrders(sort, root, builder)を呼び出して行います。しかし、それを呼び出すメソッドが不可能であったので、私はtoOrderメソッドを自分自身と呼び、結果を自分の好みに変えました。

これは、結果のすべての注文をSingularAttributePathクラスのカスタム実装に置き換えることを意味します。余分に私はPageableクラスによって使用されるSortクラスを拡張して、何がラップされ、何がないか(NaturalOrderと呼ばれる)を制御できるようにしました。しかし、私は1秒でそれに行きます。私の実装は

// 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; 

(いくつかのチェックが省略されている)、この近くに見えるリターンリストは、query.orderBy(resultlist)を呼び出すことで、クエリに追加されます。それはバックエンドのためのものです。

ラップ条件を制御するために、私はPageable(これを数行前に戻します)で使用されているSortクラスも拡張しました。私が追加したい唯一の機能は、Direction列挙型に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したがって、入力したテキストのフォーマットは事前に定義されていませんか?つまり、そのユーザーは_「これは第2グループです」_と入力することができます_これはソート順で_「これは第10のグループです」_の前に来なければなりませんか? –

関連する問題