DBFlute: B. Exists句の向上

【旧】
MemberCB cb = new MemberCB();
{
    PurchaseCB subCB = new PurchaseCB();
    subCB.query().setPurchaseCount_GreaterEqual(2);
    cb.query().setMemberId_ExistsSubQuery_PurchaseList(cb.query());
}

【新】
MemberCB cb = new MemberCB();
cb.query().existsPurchaseList(new SubQuery) {
    public void query(PurchaseCB subCB) {
        subCB.query().setPurchaseCount_GreaterEqual(2);
    }
});
※無論、「旧」のやり方も正常に動作します。


可読性と実装の安全性を考慮しました。

「新」の方はSQLのExists句に近いイメージで記述されます。
また、インデントとサブクエリ側の設定場所を強制するため、
人によっての実装の仕方にばらつきが「旧」よりも出にくいです。
(作者としてはここを非常に重要だと思っています。
 他の人のソースを読んでもおおよそ統一されていることは
 コードをメンテナンス上でとても重要なのです)

コールバックが敷居が少し高いですが、Eclipseの補完をしっかり
使えば結構サクサク、かつ、安全に実装できるものです。
http://dbflute.sandbox.seasar.org/contents/migration/migrate-070to071.html
の「コールバックのEclipseでのコード補完」をぜひご覧になって下さい。

ちなみにC#だとこうなります。

【新のC#版】
MemberCB cb = new MemberCB();
cb.Query().ExistsPurchaseList(delegate(PurchaseCB subCB) {
    subCB.Query().SetPurchaseCount_GreaterEqual(2);
});

コードの見易さはJavaを遥かに凌駕します。
(本当はJavaでもこれがやりたかったぁ。。。)

= = = = = = = = = = = = = = = = = = = = = = = = 
さらに、Exists句に関しては思い入れがあります。
それは「ちょっと複雑だけども定型的で間違え易いもの」だからです。

「子テーブルの条件で絞り込む」場合は、大抵Exists句を利用します。
頻繁ではありませんが、珍しくもない形式の条件です。
そして、とても条件の書き方は定型的です。
しかし、ちょっと複雑(相関サブクエリだし)で、しかも間違え易いです。
(作者は色んな人がこの手のSQLでバグを出していたのを何度も
 目の当たりにしました。しかも間違ったSQLはエラーを出さずに
 間違った結果でそれっぽく動いてしまうので原因発見が遅れます)

これはConditionBeanのスコープ内であるべきで、個人的には
「ConditionBeanで一番たくさん安全を買えるところ」だと思っています。
もっともっと、皆に使ってもらいたい機能なのです。
(Exists句は大抵の場合SQL的にも速いし)

それだけに可読性や実装の安全性の向上をさせたかったので、
この時期においてこの修正をさせて頂きました。
(DBFluteのExists句における最終仕様として)
= = = = = = = = = = = = = = = = = = = = = = = =