はじめに
前回はDBFluteの環境を構築し,実際にDBアクセスをしてみました。
今回はDBFluteのコア機能であるConditionBeanを実際に使ってみましょう。
お知らせ
この連載にて利用するExampleのソース(Eclipseプロジェクト)は,Subversionにて管理されており,誰もが参照することが可能です。
以下がSVNリポジトリのURLです。
H2データベースを組み込みで利用しているため,チェックアウトしてすぐに単体テストが実行できます。
また,ちょっとしたテーブル構造の確認などはDBFluteが生成したテーブル一覧HTMLにて確認できます。
今回のConditionBeanの例題プログラムも全てこのプロジェクトにて実装されています。ぜひチェックアウトしてDBFluteをいじり倒して見て下さい!
ConditionBean
条件絞り込み
Equal
まず,基本中の基本「Equal」からやってみて,条件メソッドの根本的な仕様を探っていきましょう。
条件値は全てバインド変数としてハンドリングされます。条件の組み立てはConditionBeanのquery()メソッドを必ず利用します。
続いてメソッドを補完すると,set[カラム名]_[演算子]()というメソッドが利用できます(リスト1)。
リスト1:Equal
/**
* 会員ID「3」の会員を検索
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_Tx() throws Exception {
// ## Arrange ##
final Integer expectedMemberId = 3;
final MemberCB cb = new MemberCB();
cb.query().setMemberId_Equal(expectedMemberId);
// ## Act ##
final Member member = memberBhv.selectEntityWithDeletedCheck(cb);
// ## Assert ##
assertNotNull(member);
assertEquals(expectedMemberId, member.getMemberId());
}
そして,複数条件を指定指定した場合は全てAND条件として設定されます(リスト2)。ConditionBeanではOR条件はサポートしていません(特例を除き)。代わりにUNION(後述)を利用します。
リスト2:複数条件の指定
/**
* 会員ID「1」,かつ,会員アカウント「Stojkovic」の会員を検索
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_TwoOrMoreCondition_Tx() throws Exception {
// ## Arrange ##
final Integer expectedMemberId = 1;
final String expectedMemberAccount = "Stojkovic";
final MemberCB cb = new MemberCB();
cb.query().setMemberId_Equal(expectedMemberId);
cb.query().setMemberAccount_Equal(expectedMemberAccount);
// ## Act ##
final Member member = memberBhv.selectEntityWithDeletedCheck(cb);
// ## Assert ##
assertNotNull(member);
assertEquals(expectedMemberId, member.getMemberId());
assertEquals(expectedMemberAccount, member.getMemberId());
}
もし,setMemberId_Equal()の引数にnullを入れた場合はどうなるでしょうか?
例えば,検索画面の条件入力項目において,ユーザが何も入力しなければnullもしくは空文字が来ることでしょう。そのような状況を考慮して,nullもしくは空文字が指定された場合はその条件は無効になります(リスト3,4)。
リスト3:条件引数にnullを指定
/**
* 会員IDにnullを設定
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_ArgumentNull_Tx() throws Exception {
// ## Arrange ##
final MemberCB cb = new MemberCB();
cb.query().setMemberId_Equal(null);
// ## Act & Assert ##
try {
memberBhv.selectEntityWithDeletedCheck(cb);
fail();
} catch (EntityDuplicatedException e) {
// OK
log.debug(e.getMessage());
}
}
リスト4:条件引数に空文字を指定
/**
* 会員名に空文字を設定
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_ArgumentEmptyString_Tx() throws Exception {
// ## Arrange ##
final MemberCB cb = new MemberCB();
cb.query().setMemberName_Equal("");
// ## Act ##
final int count = memberBhv.selectCount(cb);
// ## Assert ##
assertEquals("条件なしの件数と同じであること", memberBhv.getCountAll(), count);
}
よってConditionBeanでは,画面入力値の有無をif文で囲って条件付与を分岐させる必要はありません(リスト5)。この仕様は,他の条件メソッドにも当てはまります(GreaterEqualやLessThanなど)。
リスト5:画面入力値を想定した実装
/**
* 会員IDと会員名と会員ステータスを画面から入力されたと想定
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_SearchInputExample_Tx() throws Exception {
// ## Arrange ##
// これらは画面入力値を想定
final Integer memberId = 3;
final String memberName = null;
final String memberStatusCode = "FML";
final MemberCB cb = new MemberCB();
// ここで特にif文でnullチェックをする必要はない。
cb.query().setMemberId_Equal(memberId);
cb.query().setMemberName_Equal(memberName);
cb.query().setMemberStatusCode_Equal(memberStatusCode);
// ## Act & NonAssert##
// 会員ID「3」かつ会員ステータス「FML(正式会員)」という条件になる
// --> where MEMBER_ID = 3 and MEMBER_STATUS_CODE = 'FML'
final List<Member> memberList = memberBhv.selectList(cb);
log.debug(memberList);
}
また,同じカラムに対する同じ演算子の条件を再度設定した場合は,上書きになります(リスト6)。
リスト6:条件の上書き
/**
* 会員ID「3」の設定をした後,会員ID「4」を設定
*
* @throws Exception
*/
public void test_ConditionBean_Query_Equal_OverrideCondition_Tx() throws Exception {
// ## Arrange ##
final Integer beforeMemberId = 3;
final Integer afterMemberId = 4;
final MemberCB cb = new MemberCB();
cb.query().setMemberId_Equal(beforeMemberId);
cb.query().setMemberId_Equal(afterMemberId);
// ## Act ##
final Member member = memberBhv.selectEntityWithDeletedCheck(cb);
// ## Assert ##
assertNotNull(member);
assertEquals("後に設定した値が有効になること", afterMemberId, member.getMemberId());
}
しかし,この挙動は演算子によって変わります。LikeSearch(後述)は同じカラムに対する同じ演算子の条件をAND条件でつなげることに意味のあるため,これらの演算子は呼び出すたびにAND条件で条件が追加されます。
ただし,NotEqual(後述)もAND条件でつなげる意味があるのですが,NotInScope(後述)を利用することで代用できるためこちらは上書き仕様となっています。

