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 の中で最も実現が大変だった機能の一つです。