DBFlute-1.1でこうなる、最終段階! 今日は、 ExistsReferrer や LoadReferrer など、 Referrer系のインターフェース微調整のお話。
後ろの List がなくなる
ずばり、メソッド名が... 1.0.x : existsPurchaseList() 1.1から : existsPurchase() 後ろの List がなくなります。
List<Member> memberList = memberBhv.selectList(cb -> { cb.setupSelect_MemberStatus(); cb.query().existsPurchase(purchaseCB -> { cb.query().existsPurchasePayment(paymentCB -> { ... }); }); }); memberBhv.loadPurchase(memberList, purchaseCB -> { purchaseCB.query()... }
もともと List って、one-to-many の many を表すキーワードでした。 自動生成されたコードの中でリレーションを識別するもの。 極端な話、相互参照しているテーブルがあったら、 many-to-one の Purchase と、 one-to-many の Purchase が混在します。 そのときの識別として必要なのです。 ですが、ExistsReferrer や LoadReferrer など、 ConditionBean や検索の識別としては、それはほとんど不要です。 exists... や load... と言えば自動的に many とわかる 厳密には exists には AsOne がいますが、 1.1.x からは互換オプションになっていますし、 そちらは AsOne 付くので、重複は相当少ないはず。 (AsOneっていうテーブル名があったらややこしいですが...) きっかけは、Lambda。 余計な宣言が減った分、メソッド名の視認性が求められると感じました。 テーブル名と混じって後ろにListと入っていると、 何のテーブルを exists しているのかをパッと見づらいなと。 そもそも SQL でも List は付きませんし... ということで、このようにさせて頂きました。 もちろん、 isCompatibleReferrerCBMethodIdentityNameListSuffix で戻せます。
Entity の get はそのまま
Entity の getPurchaseList() はそのままです。 こっちは、List を get したり set したりするので、 getPurchase() で List が戻ってくるのは無しだなと。 もともと、複数形にしたら?とよく言われますが、 その辞書の作成にコストがかかりますし、 英語の分、規則的ではなくなるので、 複数を表す用語としてベタにListにしています。 今回、検索のオペレーションをするような箇所で、 Listを排除しましたが、リレーションを識別する プロパティ名としては List が付くことには変わりません。 複数FKなどのときに、 PurchaseByMyIdList PurchaseByMyId と、場所によって表現がズレちゃうのでいやだなとは思いましたが... よく使われる場面での視認性を優先しました。
InScopeReferrer はオプションに
InScopeReferrer は ExistsReferrer のオプションに。 厳密には、InScopeReferrer というのは無くなります。
List<Member> memberList = memberBhv.selectList(cb -> { cb.setupSelect_MemberStatus(); cb.query().existsPurchase(purchaseCB -> { cb.useInScopeSubQuery(); cb.query().existsPurchasePayment(paymentCB -> { ... }); }); });
InScopeReferrer と ExistsReferrer は、 どちらを選んでも検索結果が変わりません。 SQLに対する命令が変わるだけです。 DBFluteでは、通常は ExistsReferrer を 使ってもらうことをメインにしています。 そちらの方がパフォーマンスに優れた場面が多い と考えていて、意味的にしっくりくるからです。 ですが、状況によっては、InScope で やった方がよい場面もあると思われるので、 InScopeも選択できるようになっていました。 そう、ここは手段と目的がちょっと混在していました。 「子テーブルの存在を確認する」という目的に対して、 Exists と InScope という手段があるのですが、 その手段を選ぶ感じになっていました。 ただ、Existsは目的と一致する手段でもありました。 ExistsReferrer という目的の機能に対して、 デフォルトでは、相関サブクエリの exists 句で実現し、 InScopeのサブクエリ (InScopeSubQuery) という 手段で実現するオプションがある、そんな感じに。 これにより、コンパイルスピードの向上が見込まれます。 あまり使われない機能に対して、出力されるコード量が 多かった機能でありました。 なので、意味上のリファクタリングの話も合わせて、 これを機に整理整頓しました。 で、こっちは戻すオプションがありません。 バッサリいきました。 使っている箇所は少ないと想定しているので、 もし、移行でコンパイルエラーになったら、 existsに直して、 cb.useInScopeSubQuery(); と書いてくれればOKです。
なかなかキリがないですが...
とまあ、やっぱり Lambda とか、 いろいろと互換を崩してやっていると... 「ここまでやったら、もうこれもこうしちゃいたい」 ってのが出てきちゃいますが、キリがないですね。 コンパイルの互換に対して、 精神的な互換にはとても気をつかいます。 互換が崩れても喜んでもらえる変更であればOKですが、 そうでないことをやると、大切なものを失う可能性があります。 cb.select_MemberStatus(); cb.query().orderMemberName_Desc(); こいつらは今日、妄想していた案ですが、 「せっとあっぷせれくと」っていう、独特の響きが 開発現場の会話でスムーズに流れることを考えると、 ここはそのままがいいかなと。 selectWith_...ではたいして変わってない。 ここは精神的な互換の崩すインパクトがでかい。 addOrderBy は打ちづらい。 orderMemberName_Desc() なら補完しやすい。 cb.query().orderMemberName_Desc(); cb.query().orderBirthdate_Desc(); ただ、addしてる感がなくなってしまうのと、 その精神的な互換を崩すまでの価値があるかというと、 OrderByの登場回数を考えると、そんなんでもないかも。 query()とやっているからには、 絞り込み条件とパッと見で区別がしやすい方がよく、 意外にそのおおげさな addOrderBy が目印になる。 あと、addで補完が先頭に出てくるので、 これで order by ができることが知ってもらいやすい。 addOrder_MemberName_Desc(); うーん、中途半端だなぁ... B を打たなくていいのはうれしいけど。 中途半端であれば、そこは「まんま」を貫いた方が いいだろう。。。でも、変えるなら今しかない。。。 なんて頭をぐるぐる、ぷはーーー でも、今の Java だと、いくら Java8 でも、 ちょっとこの辺が限界かなっていうのもあります。 理想のインターフェースを考えたら、 いまはまだ中途半端な改善しかできないなと。 コンパイル気にしないのであれば、 もっと大それた改善ができるのは今も想像できていますが、 まだそれはできないなぁと。 なので、それはまた未来かなと。 ということで、このブログを書いてる時点では、 「取得・絞り込み・ソート」の三つの指定は、 とりあえず「そのまんま」という感じです。 猶予は、もう一、二週間くらいしかないでしょうから、 そこ以外のところも含めて、いろいろと悩みたいと。