OrScopeQuery

概要

複数の絞り込み条件を or で連結します。

通常の Query の連結条件は and です。OrScopeQuery を使うことで、ある範囲の複数条件の Query を or 条件にすることができます。

パフォーマンス考慮において、or と union はよく議論されます。特に、大量データのテーブルに対しての検索では、OrScopeQuery はよく吟味してから利用して下さい。

会話上では、おあすこーぷくえり と表現します。

実装方法

実装の流れ ※1.1.x (Java8版)

ConditionBean の orScopeQuery() を呼び出し、引数のコールバック(orQuery)で or 条件の Query を設定します。そのコールバック内で設定された条件同士が or で連結されます。

e.g. OrScopeQuery条件の実装手順 (Eclipseでコード補完) {MEMBER} @Java
cb.or // .or と打って enter
--

// メソッドが補完されて、引数の "orCBLambda" が選択状態に
cb.orScopeQuery(orCBLambda);
--

// cbLambdaの部分で、_ll (補完テンプレートが有効なら)
cb.orScopeQuery(_ll);
--

// 実装メソッドの空実装が自動生成される (Eclipse-3.5 以上)
cb.orScopeQuery(orCB -> {
    // 会員名称が "S" で始まる、もしくは、会員IDが 3 の会員
    orCB.query().setMemberName_LikeSearch("S", op ->: op.likePrefix());
    orCB.query().setMemberId_Equal(memberId);
});
e.g. 会員名称が "S"、もしくは、会員IDが 3 の会員 @DisplaySql
...
  from MEMBER dfloc 
 where (dfloc.MEMBER_NAME like 'S%' escape '|'
     or dfloc.MEMBER_ID = 3
       )

通常の Query と OrScopeQuery を組み合わせて利用できます。

e.g. 正式会員で、会員名称が "S" で始まる、もしくは、会員IDが 3 の会員 @Java
cb.query().setMemberStatusCode_Equal_Formalized();
cb.orScopeQuery(orCB ->: {
    orCB.query().setMemberName_LikeSearch("S", op ->: op.likePrefix());
    orCB.query().setMemberId_Equal(3);
});
e.g. 正式会員で、かつ、[会員名称が "S" で始まる、もしくは、会員IDが 3] の会員 @DisplaySql
...
  from MEMBER dfloc 
 where dfloc.MEMBER_STATUS_CODE = 'FML'
   and (dfloc.MEMBER_NAME like 'S%' escape '|'
     or dfloc.MEMBER_ID = 3
       )

実装の流れ ※1.0.x (Java6版)

ConditionBean の orScopeQuery() を呼び出し、引数のコールバック(orQuery)で or 条件の Query を設定します。そのコールバック内で設定された条件同士が or で連結されます。

e.g. OrScopeQuery条件の実装手順 (Eclipseでコード補完) {MEMBER} @Java
MemberCB cb = new MemberCB();
cb.or // .or と打って enter
--
// メソッドが補完されて、引数の "orQuery" が選択状態に
cb.orScopeQuery(orQuery)
--
// "new " (new + 空白一つ) と打って ctrl + space そして enter
cb.orScopeQuery(new )
--
// 実装メソッドの空実装が自動生成される (Eclipse-3.5 以上)
cb.orScopeQuery(new OrQuery<MemberCB>() {

    public void query(MemberCB orCB) {
        // TODO Auto-generated method stub
        
    }
})
--
// インナークラスに渡すために final をつける。
// 先にインナークラスの中で参照してから ctrl + 1 で final を補完してもOK。
final Integer memberId = 3;

// ctrl (or command) + D で不要な空行やTODOコメントを消して
// or 条件の絞り込み条件を指定
cb.orScopeQuery(new OrQuery<MemberCB>() {
    public void query(MemberCB orCB) {
        // 会員名称が "S" もしくは "J" で始まる、もしくは、会員IDが 3 の会員
        orCB.query().setMemberName_PrefixSearch("S");
        orCB.query().setMemberName_PrefixSearch("J");
        orCB.query().setMemberId_Equal(memberId);
    }
}); // セミコロンを忘れずに

or 条件の中の and 条件

or 条件の中で and 条件を利用することができます。これを OrScopeQuery の AndPart と呼びます。OrScopeQuery の中のコールバックの中で、orScopeQueryAndPart() を呼び出し、引数のコールバックの中で and 条件にしたい絞り込み条件を設定します。@since 0.9.7.3

e.g. 退会会員、もしくは、正式会員日時のなく会員IDが100以上、もしくは、生年月日のない正式会員 @Java
MemberCB cb = new MemberCB();
cb.orScopeQuery(orCB -> {
    orCB.query().setMemberStatusCode_Equal_Withdrawal();
    orCB.orScopeQueryAndPart(andCB -> {
        andCB.query().setMemberId_GreaterEqual(100);
        andCB.query().setFormalizedDatetime_IsNull();
    });
    orCB.orScopeQueryAndPart(andCB -> {
        andCB.query().setMemberStatusCode_Equal_Formalized();
        andCB.query().setBirthdate_IsNull();
    });
});
e.g. 退会会員、もしくは、正式会員日時のなく会員IDが100以上、もしくは、生年月日のない正式会員 @DisplaySql
...
  from MEMBER dfloc 
 where (dfloc.MEMBER_STATUS_CODE = 'WDL'
     or (dfloc.MEMBER_ID >= 100 and dfloc.FORMALIZED_DATETIME is null)
     or (dfloc.MEMBER_STATUS_CODE = 'FML' and dfloc.BIRTHDATE is null)
       )

OrScopeQuery を経由しない AndPart、および、AndPart 内での OrScopeQuery の呼び出しは利用できません。 (ネストした OrScopeQuery はサポートされていません)

LikeSearch の SplitBy

LikeSearch の SplitBy は、それ自身で and か or を選択できる特殊な機能です。OrScopeQuery 内で使った場合でも(AndPart も含む)、連結条件は SplitBy の仕様を優先します。

e.g. 会員名称に "S" と "t" が含まれている、もしくは、"J" で始まる会員 @Java
MemberCB cb = new MemberCB();
cb.orScopeQuery(new OrQuery<MemberCB>() {
    public void query(MemberCB orCB) {
        LikeSearchOption option
            = new LikeSearchOption().likeContain().splitBySpace();
        orCB.query().setMemberName_LikeSearch("S t", option);
        orCB.query().setMemberName_PrefixSearch("J");
    }
});
e.g. 会員名称に "S" もしくは "M" で始まる、もしくは、"J" で始まる会員 @DisplaySql
...
  from MEMBER dfloc 
 where ((dfloc.MEMBER_NAME like '%S%' escape '|' and dfloc.MEMBER_NAME like '%t%' escape '|')
     or dfloc.MEMBER_NAME like 'J%' escape '|'
       )
e.g. 会員名称に "S" もしくは "M" で始まる、もしくは、"J" で始まる会員 @Java
MemberCB cb = new MemberCB();
cb.orScopeQuery(new OrQuery<MemberCB>() {
    public void query(MemberCB orCB) {
        LikeSearchOption option
            = new LikeSearchOption().likePrefix().splitBySpace().asOrSplit();
        orCB.query().setMemberName_LikeSearch("S M", option);
        orCB.query().setMemberName_PrefixSearch("J");
    }
});
e.g. 会員名称に "S" もしくは "M" で始まる、もしくは、"J" で始まる会員 @DisplaySql
...
  from MEMBER dfloc 
 where (dfloc.MEMBER_NAME like 'S%' escape '|'
     or dfloc.MEMBER_NAME like 'M%' escape '|'
     or dfloc.MEMBER_NAME like 'J%' escape '|'
       )

そもそも AsOrSplit は、内部的に OrScopeQuery を利用して実現しています。

日付のFromTo (DateFromTo)

OrScopeQuery の中で日付の FromTo (DateFromTo) 条件を利用した場合は、FromTo 条件は and 固定で連結されます。(and で利用することに意味がある機能のため) @since 0.9.9.4A

メソッド仕様

コールバックでは絞り込み条件のみ

OrScopeQuery 内では、絞り込み条件のみ設定できます。以下の機能が利用できます。

  • query() 経由で利用できる絞り込み条件
  • OnClause, InlineView
  • ColumnQuery

※SetupSelect や UnionQuery など、それ以外の機能を呼び出してはいけません。

条件が一つだけの場合

業務的には、Query を使って設定したときと同じ動きになります。SQL上では、その唯一の条件が OrScopeQuery の名残である括弧で囲まれます。

条件が全て無効になった場合

例えば、OrScopeQuery 内の条件値が全て null で条件が成立しなかった場合、 OrScopeQuery を呼び出さなかったのと同じ動きになります。

同カラム同条件に対する複数指定は有効に

通常の Query では、絞り込み条件の同カラムに対する複数指定は、ConditionKey 次第では上書きになりますが、OrScopeQuery 内では(AndPart も含む)、呼び出した分だけ条件が付与されます。

e.g. 会員IDが 1 もしくは 3 の会員 @Java
cb.orScopeQuery(orCB -> {
    orCB.query().setMemberId_Equal(1);
    orCB.query().setMemberId_Equal(3);
});
e.g. 会員IDが 1 もしくは 3 の会員 @DisplaySql
...
  from MEMBER dfloc 
 where (dfloc.MEMBER_ID = 1
     or dfloc.MEMBER_ID = 3
       )

但し、同カラムに対する同じ条件値での複数指定(業務的に無意味な条件)も、呼び出した分だけ条件が付与されてしまいます。 (通常の Query では、その旨を伝えるデバッグログが出力されて無視される)

サブクエリのCBは独立

OrScopeQuery の中で ExistsReferrer などのサブクエリを利用する場合に、サブクエリ内の ConditionBean の連結条件に特に変わりはありません。OrScopeQuery の状態が引き継がれることはありませんので、サブクエリの中で OrScopeQuery を利用する場合は、明示的に呼び出して設定します。

無効な呼び出し

以下のような呼び出しは無効です。

  • OrScopeQuery 内でない場所での AndPart の呼び出し (業務的に無意味)
  • AndPart 内での (ネストした)OrScopeQuery の呼び出し (サポートされない)

ソースコードリーディングのススメ

OrScopeQuery は、ConditionBean の中で最も実現が大変だった機能の一つです。