検索条件のカスタマイズ

最終更新日: 2021年12月15日
R8 | R9

クライテリア

「クライテリア」は、Wagby内部で利用している、検索条件を管理するクラスです。SQL に相当する表現能力があり、利用するデータベースに依存しないことや、コンパイル時に型をチェックしエラーを検出できるといったメリットがあります。

図1 クライテリアの位置づけ

図1にあるように、ユーザが入力した「検索条件」は、Webフォームから「コンディションモデル」という形で Wagby に取り込まれます。コンディションモデルはさらに「クライテリア」に変換されます。このクライテリアが SQL に変換され、データベースへの問い合わせを行います。

クライテリアは Wagby が同梱している O/R Mapper ミドルウェア Hibernate が提供するものです。クライテリアから SQL への変換は、Hibernate が行います。

クライテリアをカスタマイズするメリット

Wagby の標準では、複数項目の検索条件はすべて AND 結合となります。例えば、顧客モデル(customer) の mainstaff 項目が "花子" または substaff 項目が "花子" という検索は、標準機能では実現できません。(標準機能では、mainstaff が "花子" かつ substaff も "花子" という AND 結合になります。)

クライテリアをカスタマイズすることで、複数項目の OR 検索を実現できます。

例 OR検索 [1]

要件

検索フォームで指定された担当者項目の検索条件値を主担当者、副担当者との OR 検索とする例を考えます。

図2 要件イメージ

具体的には、顧客モデル(customer) の mainstaff 項目が "ジャスミン花子" または substaff 項目が "ジャスミン花子" という検索を実現できるようにします。

用意するスクリプト

「画面 > スクリプト > ヘルパ > 検索」を用意します。

図3 スクリプトの作成
WEB-INF/script/<モデルID> フォルダに <モデルID>CriteriaConverter_convert.js が生成されます。
  // customerモデルを定義すると CustomerMeta クラスは自動生成されます。
  var meta = new Packages.jp.jasminesoft.wagby.model.customer.CustomerMeta();
  // スクリプトでは criteria.like() 等を利用すると
  // Can't unambiguously select between fixed arity signatures
  // エラーが発生することがあるため、$r を使って検索条件を組み立てます。
  // criteria のメソッドは add() のみを使って下さい。
  var $r = criteria.restrictions();
  // "mainstaff" like '%ジャスミン花子%' OR "substaff" like '%ジャスミン花子%'
  criteria.add(
    $r.or(
      $r.like(meta.mainstaff, customer_c.mainstaff),
      $r.like(meta.substaff, customer_c.mainstaff)
    )
  );
  customer_c.mainstaff = null; // 元の検索条件は消去しておく。(*1)
  • スクリプト内で暗黙オブジェクト criteria を利用できます。最初に criteria.restrictions() の返戻値を $r で受けるようにします。この $r を使って検索条件を組み立てます。
  • 暗黙オブジェクト criteria に対しては add メソッドのみが利用できます。
  • criteria を用いた検索条件の指定では、対象項目名は文字列ではなく、Wagbyが提供するメタクラスを使います。例えばcustomerモデルを定義するとメタクラス CustomerMeta が自動生成されます。これは項目名と型の情報(メタデータ)を保持する特別なクラスです。メタクラスを使うことでスペルミスによる実行時エラーといった、デバッグしにくい問題を回避することができます。

元の検索条件を消去する

上記スクリプトで (*1) の処理を行わないと、次の SQL が実行されてしまいます。

WHERE
    mainstaff LIKE ‘%ジャスミン花子%’
AND (
       mainstaff LIKE ‘%ジャスミン花子%’
    OR substaff LIKE ‘%ジャスミン花子%’
)
AND...

WHERE 句の最初の mainstaff LIKE... は自動生成コードが付与したものですが、この要件では不要です。そのため、元の検索条件を null で上書きして、この SQL が生成されないようにします。コンディションモデルからクライテリアに変換されたとき、内部では criteria.like(meta.mainstaff, null) というコードと解釈されますが、第二引数が null の criteria は無視されるため期待どおりの動作となります。

例 OR検索 [2]

項目 item1 に対して次のような検索を行う要件を想定します。

item1='1' or item1='2' or item1='3'...

この場合、配列 ['1','2','3'] を事前に用意し、この配列を引数に渡してください。配列が渡された場合、内部で OR 扱いとします。

チェックボックスへの OR 検索

チェックボックス型の項目 item1 に、検索条件の初期値として "OR 1 2 3" という文字列がセットされていたとします。 この文字列を解釈し、文字配列にして検索条件とするスクリプトの例を示します。

var item1 = model1_c.item1;
if (item1 !== null) {
    if (item1.startsWith("OR ")) {
        item1 = item1.substring(2);// 先頭の "OR " を除き、空白区切りの文字列を配列にする。
        var array = item1.split(/\s/);
        //for (i = 0; i < array.length; i++) {
        //    print(array[i]);
        //}
        var meta = new Packages.jp.jasminesoft.wagby.model.model1.Model1Meta();
        var $r = criteria.restrictions();
        criteria.add(
            $r.eq(meta.item1, array)
        );
        model1_c.item1 = null;// 元々の検索値 "OR 1 2 3" 文字列を消去する。
    }
}
チェックボックス型項目は、内部では上のように配列を渡すことで OR 検索を実現しています。

クライテリアの詳細

クライテリアの定義方法について、具体的なコード例で説明します。

  // criteria.add() を使うと AND で検索条件が追加されます。
  // WHERE "mainstaff" LIKE '%花子%' AND "substaff" LIKE '%花子%'
  criteria.add($r.like(meta.mainstaff, "花子"));
  criteria.add($r.like(meta.substaff, "花子"));
  // $r.and() でも同様に AND で検索条件が追加されます。
  // 次の記述方法でも同じ SQL が生成されます。
  // WHERE "mainstaff" LIKE '%花子%' AND "substaff" LIKE '%花子%'
  criteria.add(
      $r.and(
        $r.like(meta.mainstaff, "花子"),
        $r.like(meta.substaff, "花子")
      )
  );
  // $r.like(), $r.and() の戻り値を変数に格納することも可能です。
  // 次の記述方法でも同じ SQL が生成されます。
  // WHERE "mainstaff" LIKE '%花子%' AND "substaff" LIKE '%花子%'
  var likeCriterion01 = $r.like(meta.mainstaff, "花子");
  var likeCriterion02 = $r.like(meta.substaff, "花子");
  var andCriterion = $r.and(likeCriterion01, likeCriterion02);
  criteria.add(andCriterion);
  // $r.or() を使うことで OR 検索を行うことができます。
  // WHERE "mainstaff" LIKE '%花子%' OR "substaff" LIKE '%花子%'
  criteria.add(
      $r.or(
        $r.like(meta.mainstaff, "花子"),
        $r.like(meta.substaff, "花子")
      )
  );
  // 引数が null の場合はその条件は無視されます。
  // WHERE "substaff" LIKE '%花子%'
  criteria.add(
      $r.or(
        $r.like(meta.mainstaff, null),
        $r.like(meta.substaff, "花子")
      )
  );
  // 単一項目への OR 検索は引数を追加するだけで実現可能です。
  // WHERE "mainstaff" LIKE '%花子%' OR "mainstaff" LIKE '%太郎%' OR "mainstaff" LIKE '%次郎%'
  criteria.add($r.like(meta.mainstaff, "花子", "太郎", "次郎"));
  // 複雑な検索条件。
  // "住所が「沖縄」のお客様で、かつ、主担当が「花子」
  //  または、
  //  住所が「北海道」のお客様で、かつ、主担当が「次郎」"
  // となっている顧客データを抽出する。
  // WHERE (("address" LIKE '%沖縄%' AND "mainstaff" LIKE '%花子%') OR ("address" LIKE '%北海道%' AND "mainstaff" LIKE '%次郎%' ))
  criteria.add(
      $r.or(
        $r.and(
          $r.like(meta.address, "沖縄"),
          $r.like(meta.mainstaff, "花子")
        ),
        $r.and(
          $r.like(meta.address, "北海道"),
          $r.like(meta.mainstaff, "次郎")
        )
      )
  );

利用できる検索条件

$r では次の関数が用意されています。 これらを $r.or() や $r.and() でつなげていくことになります。

提供されるメソッド説明コードの記述方法
eq等しいeq(meta, values)
ne等しくないne(meta, values)
like文字列の部分一致like(meta, values)
likePrefix文字列の前方一致likePrefix(meta, values)
likeSuffix文字列の後方一致likeSuffix(meta, values)
ge以上ge(meta, value)
gtより大きいgt(meta, value)
le以下le(meta, value)
ltより小さいlt(meta, value)
between範囲検索between(meta, lowValue, highValue)
isNullnullかどうかisNull(meta)
isNotNullnullでないかどうかisNotNull(meta)
1. 引数が value ではなく、values となっている関数は複数の値を指定することが可能です。
2. 複数の値を指定した場合 eq(), like(), likePrefix(), likeSuffix()は OR 条件となり、ne() は AND 条件となります。

ソートの指定

Criteria プログラミングで ORDER BY 句を実現することができます。ここでは model1 モデルの item1, item2 項目でソートする例を示します。

  // ORDER BY item1 DESC, item2 ASC を指定する。
var Order = Java.type("org.hibernate.criterion.Order");
var meta = new Packages.jp.jasminesoft.wagby.model.model1.Model1Meta();
criteria.addOrder(Order.desc(meta.item1.name()))
// 続けて追加すれば複数指定することも可能。
criteria.addOrder(Order.asc(meta.item2.name()))

このスクリプトの後に Wagby 標準の ORDER BY が追加されますが、スクリプト内で指定しておくことで標準の ORDER BY よりも優先されるので、意図した順に並べることができます。

仕様・制約

  • ダウンロード処理では、このクライテリアは使われません。ダウンロード処理で検索式をカスタマイズする場合は、生成された Java コードを直接、修正する必要があります。 R8.3.3 で改善されました。ダウンロード処理で Download<モデルID>CriteriaConverter_convert.js スクリプトが呼び出されます。R8.3.4 で、このスクリプトをDesignerで直接、作成できるようになりました。(ヘルパ > ダウンロード、を指定してください)
  • 全文検索機能を有効にしたとき、このクライテリアは使われません。(全文検索機能を利用した場合、クライテリアとは別方式の検索処理となっています。)
  • 一覧表示の集計機能では、このクライテリアは使われません。(一覧表示の集計機能は、クライテリアとは別方式の検索処理となっています。)