外だしSQLのカーソルとカウントについて

68 views
Skip to first unread message

mokkouyou

unread,
Mar 15, 2022, 2:31:44 AM3/15/22
to DBFluteユーザの集い
いつもお世話になっております。

さっそくですが、
外だしSQLでカーソル検索を行いたいのですが、
事前にカウントを発行したいと思っております。
この場合、SQLファイルは別にしなくてはいけないでしょうか?

ページング検索のように条件付けで出来るといいなと思いましたが、

・スカラ検索出来ない
・手動ページングでカウントだけ出来ない?

ことから、上記の様なことは出来ないのかな?と思った次第です。

以上よろしくお願いいたします。

kubo

unread,
Mar 15, 2022, 3:16:40 AM3/15/22
to DBFluteユーザの集い
jfluteです。mokkouyouさん、こんにちは。問い合わせありがとうございますー。

以前も話題になったような記憶があるので、ちょっと調べてみますね。

kubo

unread,
Mar 15, 2022, 3:19:35 AM3/15/22
to DBFluteユーザの集い
jfluteです。

取り急ぎ、こんなサンプルがありました。
カーソル検索とカウント検索というよりも、カーソル検索とページング検索ってところですね。

// PurchaseBhv_selectPaymentCompletePurchase.sql
// Example for Cursor and Paging select
https://github.com/dbflute-test/dbflute-test-active-hangar/blob/master/src/main/resources/org/docksidestage/hangar/dbflute/exbhv/PurchaseBhv_selectPaymentCompletePurchase.sql

何か応用できないかなと。(また後で見てみます)

mokkouyou

unread,
Mar 15, 2022, 9:42:23 AM3/15/22
to DBFluteユーザの集い
jfluteさん

ありがとうございます。
外だしSQLのカーソル検索回り、マニュアルページング周りにそのあたりの説明まではあり、
両方いけるところまではたどりつけたんですが、

selectPageでカウントだけする方法、
またはカウントだけできるメソッドがあればよかったんですが、
ちょっと処理追ってみても出来そうになく、

多少コストかかるけどページの件数1にして総件数だけ取るしかないのかなといった感じでした。

このあたり何かありましたらご教授いただければと思います。


1件検索は説明にも記載いたているとおり、マニュアルページングならではの課題・検討点があったり、
そもそも謎処理になりかねないのが難点。

カウントとカーソル検索2つにした場合、
別のpmbに等しく条件設定する必要があったりファイルが分かれることからも、
メンテナンス周りが少し難点かなといった感想です。

※特にmysqlなので事前にカウントで取得上限ではじきたいので、シンプルな方法があると助かります。

以上よろしくお願いいたします


2022年3月15日火曜日 16:19:35 UTC+9 jflute:

kubo

unread,
Mar 15, 2022, 12:17:47 PM3/15/22
to DBFluteユーザの集い
jfluteです。色々と調べてみました。


まず現状、TypedParameterBeanを使った場合、カーソル検索とカウント検索を同居させることができません。

ExクラスでEntityHandlingPmbインターフェースをimplemenentsすればいけるかな?と思ったのですが...
TypedParameterBeanは、戻り値の型をGenericで指定することで型付きにしているので、
実際にやってみるとCursorのVoidとカウントのIntegerでGenericミスマッチのコンパイルエラーになってしまいます。


ページング検索とカーソル検索の同居は、そのGeneric部分をDBFlute Engineが特別制御していることで実現できています。

同様な感じで、特別制御を入れてカウント検索も同居できるにすれば実現できるかもですが、
ページングと違ってカウント検索であることが自動では読み取りづらいので、パッとできるかどうかはわかりません。
(+scalar+を指定することでスカラー値の判断はできるが、型が判断できない...)


一方で、現状でもちょこっと工夫することで同居させて互いの検索を実行する方法はありました。

カウント検索の方では TypedParameterBean を使わず、traditionalStyle() で実行します。
要はこちらは型付きの制限がないので、辻褄が合えば動くということですね。

// SQL, isCursorHandling()で分岐させている
https://github.com/dbflute-test/dbflute-test-active-dockside/blob/master/src/main/resources/org/docksidestage/dockside/dbflute/exbhv/whitebox/pmbean/MemberBhv_selectCursorWithScalarMember.sql

// テストクラス、カーソル検索とカウント検索の両方
https://github.com/dbflute-test/dbflute-test-active-dockside/blob/master/src/test/java/org/docksidestage/dockside/dbflute/whitebox/outsidesql/WxOutsideSqlCursorTest.java#L206

// ParameterBeanのExクラス、booleanで制御
https://github.com/dbflute-test/dbflute-test-active-dockside/blob/master/src/main/java/org/docksidestage/dockside/dbflute/exbhv/pmbean/CursorWithScalarMemberPmb.java


以下、traditionalStyle()を使ってカウント検索。
ParameterBeanのnewのところでasScalarHandling()を呼び出して切り替えている。

// ## Arrange ##
String path = MemberBhv.PATH_whitebox_pmbean_selectCursorWithScalarMember;
CursorWithScalarMemberPmb pmb = new
CursorWithScalarMemberPmb().asScalarHandling();
Class<Integer> entityType = Integer.class;

// ## Act ##
OptionalEntity<Integer> optCount =
memberBhv.outsideSql().traditionalStyle().selectEntity(path, pmb,
entityType);


業務実装の期限があるのであれば、取り急ぎこちらの方法でいかがでしょうか?

mokkouyou

unread,
Mar 15, 2022, 7:43:11 PM3/15/22
to dbf...@googlegroups.com
jfluteさん

traditional試してみますね。ありがとうございます。
そして懐かしい!


2022年3月16日(水) 1:17 kubo <dbf...@gmail.com>:
> --
> このメールは Google グループのグループ「DBFluteユーザの集い」の登録者に送られています。
> このグループから退会し、グループからのメールの配信を停止するには dbflute+u...@googlegroups.com にメールを送信してください。
> このディスカッションをウェブ上で閲覧するには、https://groups.google.com/d/msgid/dbflute/CAALfU-C%3DWVPrCi%2BvnZK3BiQRTNdvzKFqyiKzWHs7YczO8f0D4g%40mail.gmail.com にアクセスしてください。



--
mokkouyou
mokk...@gmail.com

mokkouyou

unread,
Mar 15, 2022, 10:50:34 PM3/15/22
to DBFluteユーザの集い
jfluteさん

ざっくりですが
確認できました。ありがとうございました。
#副次的にはテンプレートメソッド化もやりたかったのでそちらの道筋もちょっと見えてきました。

2022年3月16日水曜日 8:43:11 UTC+9 mokkouyou:

kubo

unread,
Mar 16, 2022, 4:48:42 AM3/16/22
to DBFluteユーザの集い
jfluteです。確認ありがとうございます。

とりあえずは、traditionalStyle()での回避でお願いしますm(_ _)m。


もしやるとしたら...型が取れないので、指定するしか無くなっちゃうな。
+cursor+
+scalar: Integer+

もしくは、カウントしかやらないだろうから...
+cursor+
+count+
というのでもいいのかもしれない。

mokkouyou

unread,
Mar 18, 2022, 4:26:42 AM3/18/22
to dbf...@googlegroups.com
jfluteさん

心配性でscalarの結果を無駄にLongにしましたので、指定出来てもいいなぁ~という気もしますが、
そもそも件数でInteger範囲越えるようならそもそもそれどころじゃない地獄ですね。

なお余談になりますが、
生成されるカーソルクラスがInterface(next, acceptだけでも)持ってるといいなぁとテンプレートメソッド化において思いました。
(要望といいうか、感想)

たとえば、
Csvに出力する各種機能群など、単発機能でなければ、
だいぶ共通化出来る部分はありますので
生成されたTypeSafeなカーソルハンドラーを使わず、
CursorHandlerを自前実装したCsv出力用のテンプレートクラスを作り、
定型的になる処理を実装、
また、カーソル回りも共通ですので、
1行分の処理だけ(TypeSafeに)サブクラスに持たせたかったので、
handleの処理で定型と思われるacceptしてループ回して1行分の処理というところにおいて、
抽象化されたacceptとnextが必要となりました。

template書き換えと悩んだのですが、
自前でIF作って、ExCursorにimplementsさせました。
そもそも論みたいなのをあきらめてしまえば、
該当ハンドラーの利用にて必要な実装の1部だと思えばコンパイルエラー検知も出来るしいいかなと。


テンプレートのhandler(ここで抽象定義が欲しい)
abstract class HogeHogeCursorHandler<CUROSR extends ICursor>
implements CursorHandler

実現サブクラス(カーソルの具体的な型情報)
class ExHogeHogeCursorHandler extends HogeHogeCursorHandler<HogeCursor>

カーソルクラス(Ex)
HogeCursor extends BsHogeCursor implements ICursor {
//生成後にimple追加

こういう処理何となくありそうなのですが、みなさんどうやってるんですかね。
何かの助けになればと思いまして、情報共有もかねて・・・
(バッドプラクティスならそれはそれで残ればいいや)

2022年3月16日(水) 17:48 kubo <dbf...@gmail.com>:
> --
> このメールは Google グループのグループ「DBFluteユーザの集い」の登録者に送られています。
> このグループから退会し、グループからのメールの配信を停止するには dbflute+u...@googlegroups.com にメールを送信してください。
> このディスカッションをウェブ上で閲覧するには、https://groups.google.com/d/msgid/dbflute/CAALfU-BypTw_YHQGebacEw0CQi8zjLe_%2BsCFchH3RfPZVOGmfw%40mail.gmail.com にアクセスしてください。



--
mokkouyou
mokk...@gmail.com

kubo

unread,
Mar 19, 2022, 1:23:24 AM3/19/22
to DBFluteユーザの集い
jfluteです。

> 心配性でscalarの結果を無駄にLongにしましたので、指定出来てもいいなぁ~という気もしますが、
> そもそも件数でInteger範囲越えるようならそもそもそれどころじゃない地獄ですね。

なるほど、昔からのジレンマですね。
RDBが大量データ苦手なので今もCBのselectCount()はint固定ですが、いつか困る日が来るのか...

count限定ではなくscalarという扱いにして、型を指定しもらうようにとかすれば自由にはなるので、
やるとなったらそっち方が安心かもですね。参考にさせて頂きます。ありがとうございます。

+cursor+
+scalar: Long+



> 生成されるカーソルクラスがInterface(next, acceptだけでも)持ってるといいなぁとテンプレートメソッド化において思いました。

こういうイメージですかね

BsXxxCursorHandler implements CursorHandler
BsXxxCursor // 何もimplementsない

 ↓↓↓ 第一段階: Cursorクラスにインターフェースを

BsXxxCursorHandler implements CursorHandler
BsXxxCursor implements なんとかCursor

 ↓↓↓ 第二段階: さらにHandlerをGenericに

BsXxxCursorHandler<XxxCursor> implements CursorHandler
BsXxxCursor implements なんとかCursor

少なくともCursorクラスにインターフェースを付けるのは良さそうですね。
Genericは互換が大丈夫か?パッとまだ見極められてません。
(少し大きめのバージョンアップなら良いかなってところですが)


一方で、Exクラスにアプリ独自のインターフェースをimplementsさせるのは、
元々想定していた利用で、それでアプリは自由に抽象化させられるかなというところで、
そこまでBs部分の抽象化は気にしていなかったというのはあります。
(Cursorに限らずEntityとかExクラスにインターフェースを付けるのは、わりとオススメのやり方ではあります)


> こういう処理何となくありそうなのですが、みなさんどうやってるんですかね。
> 何かの助けになればと思いまして、情報共有もかねて・・

情報共有ありがとうございます!
こういうのが知見になっていきますし、DBFluteの改善の参考にもなります。

kubo

unread,
Apr 17, 2022, 4:34:32 AM4/17/22
to DBFluteユーザの集い
jfluteです。

> 少なくともCursorクラスにインターフェースを付けるのは良さそうですね。

1.2.6よりインターフェースを付けるようにします。

// DBFlute Runtime: make Cursor interface for OutsideSql cursor class
**
 * The accessor of cursor. <br>
 * Basically implemented by generated Cursor classes for OutsideSql.
 * @author jflute
 * @since 1.2.6 (2022/04/17 Sunday)
 */
public interface CursorAccessor {

    /**
     * Accept the result set.
     * @param rs The cursor (result set) for the query, which has first pointer. (NotNull)
     */
    void accept(ResultSet rs);

    /**
     * Get the wrapped cursor (result set).
     * @return The instance of result set. (NotNull)
     */
    ResultSet cursor();

    /**
     * Move to next result.
     * @return Does the next result exist?
     * @throws SQLException When it fails to move the cursor to next point.
     */
    boolean next() throws SQLException;
}
Reply all
Reply to author
Forward
0 new messages