6

私は、当社が高度に構成可能なデータベース検索サービスを持っている立場にいます。このサービスでは、プログラムでクエリを構成することが非常に便利です。Criteria API は強力ですが、開発者の 1 人がデータ オブジェクトの 1 つをリファクタリングすると、ユニット テストを実行するか、さらに悪いことに、実際の運用環境でテストを実行するまで、基準の制限は違反していることを示しません。最近、リファクタリング プロジェクトの作業時間が予想外に 2 倍になりました。これは、プロジェクト計画のギャップであり、実際にどれくらいの時間がかかるかを知っていれば、おそらく別のアプローチをとっていたでしょう。

この問題を解決するために Example API を使用したいと思います。Java コンパイラーは、実際の POJO プロパティで「where」条件を指定している場合、クエリが失敗したことを大声で示すことができます。ただし、サンプル API には非常に多くの機能しかなく、多くの点で制限があります。次の例を見てください

 Product product = new Product();
 product.setName("P%");
 Example prdExample = Example.create(product);
 prdExample.excludeProperty("price");
 prdExample.enableLike();
 prdExample.ignoreCase();

ここでは、プロパティ「name」に対してクエリが実行されています (「P%」などの名前)。フィールド「name」を削除または名前変更すると、すぐにわかります。しかし、物件の「価格」はどうでしょうか。Product オブジェクトにはデフォルト値があるため除外されているため、「price」プロパティ名を除外フィルターに渡しています。「価格」が削除された場合、このクエリは構文的に無効になり、実行時までわかりません。ラメ。

もう 1 つの問題 - 2 つ目の where 句を追加するとどうなるでしょうか。

 product.setPromo("Discounts up to 10%");

enableLike() の呼び出しにより、この例はプロモーション テキスト「最大 10% の割引」だけでなく、「最大 10,000,000 ドルの割引」またはその他の一致するテキストにも一致します。一般に、 enableLike() や ignoreCase() などの Example オブジェクトのクエリ全体の変更は、チェック対象のすべてのプロパティに常に適用できるとは限りません。

これが 3 番目の主要な問題です。他の特別な基準についてはどうでしょうか。標準のサンプル フレームワークを使用して、価格が 10 ドルを超えるすべての製品を入手する方法はありません。結果をプロモーションで降順に並べ替える方法はありません。製品オブジェクトが一部の製造元に結合されている場合、関連する製造元オブジェクトに基準を追加する方法もありません。製造元の基準で FetchMode を安全に指定する方法もありません (ただし、これは一般的に Criteria API の問題です - 無効なフェッチされた関係は黙って失敗し、時限爆弾のようになります)

上記のすべての例では、Criteria API に戻って、プロパティの文字列表現を使用してクエリを作成する必要があります。これも、サンプル クエリの最大のメリットを排除しています。

必要なコンパイル時のアドバイスを得ることができるサンプル API に代わるものは何ですか?

4

3 に答える 3

5

私の会社では、開発者にペット プロジェクト (Google のように) を実験して作業できる日を与えており、上記の制限を回避しながらサンプル クエリを使用するためのフレームワークの作業に時間を費やしました。クエリの例に関心のある他の人にも役立つものを思いつきました。Product の例を使用したフレームワークのサンプルを次に示します。

 Criteria criteriaQuery = session.createCriteria(Product.class);

 Restrictions<Product> restrictions = Restrictions.create(Product.class);
 Product example = restrictions.getQueryObject();
 example.setName(restrictions.like("N%"));
 example.setPromo("Discounts up to 10%");

 restrictions.addRestrictions(criteriaQuery);

このフレームワークでは基準を明示的に設定する必要があるため、「価格」フィールドのデフォルト値の問題は存在しなくなりました。クエリ全体の enableLike() を持つという 2 番目の問題はなくなりました。マッチャーは「名前」フィールドのみに存在します。

質問で言及されている他の問題も、このフレームワークでは解消されています。実装例を次に示します。

 product.setPrice(restrictions.gt(10)); // price > 10
 product.setPromo(restrictions.order(false)); // order by promo desc
 Restrictions<Manufacturer> manufacturerRestrictions 
        = Restrictions.create(Manufacturer.class);
 //configure manuf restrictions in the same manner...
 product.setManufacturer(restrictions.join(manufacturerRestrictions)); 
 /* there are also joinSet() and joinList() methods
  for one-to-many relationships as well */

さらに高度な制限を利用できます。

 product.setPrice(restrictions.between(45,55));
 product.setManufacturer(restrictions.fetch(FetchMode.JOIN));
 product.setName(restrictions.or("Foo", "Bar"));

同僚にフレームワークを見せた後、彼は、多くのデータ マップ オブジェクトにはプライベート セッターがあり、この種の基準設定も困難になっていると述べました (Example API の別の問題です!)。だから、私もそれを説明しました。セッターを使用する代わりに、ゲッターもクエリ可能です。

 restrictions.is(product.getName()).eq("Foo");
 restrictions.is(product.getPrice()).gt(10);
 restrictions.is(product.getPromo()).order(false);

また、型の安全性を高めるために、オブジェクトに追加のチェックを追加しました。たとえば、相対基準 (gt、ge、le、lt) にはすべて値が必要です。パラメータの同等のものを拡張します。また、上記のスタイルで getter を使用し、getter に @Transient アノテーションが存在する場合、実行時エラーがスローされます。

しかし、待ってください。

Hibernate のビルトイン Restrictions ユーティリティを静的にインポートできるので、コードを非常に冗長にせずに criteria.addRestriction(eq("name", "foo")) のようなことができるのが好きなら、そのためのオプションもあります。 .

 Restrictions<Product> restrictions = new Restrictions<Product>(){
       public void query(Product queryObject){
         queryObject.setPrice(gt(10));
         queryObject.setPromo(order(false));
         //gt() and order() inherited from Restrictions
       }            
 }

フィードバックをお寄せいただきありがとうございます。興味のある方のために、コードを Sourceforge に投稿しました。http://sourceforge.net/projects/hqbe2/

于 2010-09-12T04:24:59.193 に答える
1

Querydslを見てください。彼らの JPA/Hibernate モジュールにはコード生成が必要です。彼らの Java コレクション モジュールはプロキシを使用していますが、現時点では JPA/Hibernate では使用できません。

于 2013-12-30T10:47:11.850 に答える
1

APIは素晴らしいですね!

Restrictions.order(boolean) はコントロール カップリングのようなにおいがします。boolean 引数の値が何を表しているのか、少し不明確です。

orderAscending() と orderDescending() で置換または補足することをお勧めします。

于 2010-09-13T16:53:05.847 に答える