DBアクセスを定番化しよう DBFlute入門

第5回 外だしSQLの基本

この記事を読むのに必要な時間:およそ 4 分

Sql2Entityによる外だし支援

「実行の仕方」をみて,ちょっと面倒だと思いませんでしたか? 具体的には,独自の引数のBeanと独自の戻り値のEntityを定義するのが煩雑に思えませんでしょうか? 煩雑なだけでなく,Select句に定義した名前とEntityに定義したプロパティ名がスペルミスなどで食い違う可能性がバグの温床ではないかと思えるのではないでしょうか?

その通りです。S2Daoで外だしSQLを実装する際の弱点はまさしくここでした。

DBFluteはこういったところを見逃しません。おおいに支援します。

Sql2Entityと呼ばれる支援機能により,これら「引数のBean,戻り値のBean」を自動生成します。

CustomizeEntityの自動生成

SQLの行コメントとして,戻り値Entityのクラス名を定義します。

「--」に続いて,⁠#Xxx#」という形式でクラス名を記述します。

リスト3:Sql2Entityで戻り値Entityを自動生成するSQLのサンプル-SQLファイル

-- #MemberWithMaxPurchasePrice#

-- 会員IDと名称の前方一致で絞り込んで,会員一覧と購入最大価格を検索。
-- 絞り込み条件はそれぞれ値がnullじゃければ評価する。
select member.MEMBER_ID
     , member.MEMBER_NAME
...(以下変わらず)

この一行を足して,DBFluteクライアントに置いてあるsql2entity.bat(.sh)を実行して下さい。

すると,なにやらコンソールにログが流れて見事成功すると,⁠Select句の構成と同じ構成のEntityクラス」が指定された名前で生成されます。そのクラスは「xxx.exentity.customize」配下に生成されます。そのクラスを先ほどの「手動で独自に定義したEntity」に代わって利用することが可能です。

このSql2Entityでの生成を利用することにより,煩雑さが解消されると同時に「Select句の名称とEntityの名称が食い違うことがない」という安全性を得ることができます。

実はSql2Entityは,該当のSQLを実際にDBに実行しています。

実行することにより,JDBC経由でそのSQLの結果セットのメタ情報が取得でき,Select句の構成を知ることができます。その情報を使って自動生成しているのです。よって,Select句の名称とEntityの名称が食い違うことがないのです。

これは,2Way-SQLを採用することによる一番の恩恵とも言えるかもしれません。2Way-SQLでなければこのようなことは実現できません。

また,SQLの文法が正しくなければこのSql2Entityは失敗します。先ほど,2Way-SQLの説明で,ツール上でSQLの文法のチェックを行うということを説明いたしましたが,このSql2EntityがまさしくSQLの文法チェックにもなり得ます。

このSql2Entityで自動生成されたEntityをDBFluteでは「CustomizeEntity」と呼びます(これに対して,テーブル単位で自動生成されたEntityを「DomainEntity」と呼びます⁠⁠。

ParameterBeanの自動生成

さらに,引数のBeanも自動生成してしまいましょう。

SQLの行コメントとして,引数のBeanのクラス名を定義します。⁠--」に続いて,⁠!Xxx!」という形式でクラス名を記述します。

また,パラメータのプロパティを行コメントで定義します。⁠--」に続いて,⁠!![Type] [Name]!!」という形式でプロパティの型と名前を記述します。

リスト4:Sql2Entityで引数Beanを自動生成するSQLのサンプル-SQLファイル

-- #MemberWithMaxPurchasePrice#

-- !MemberWithMaxPurchasePricePmb!
-- !!Integer memberId!!
-- !!String memberName!!

-- 会員IDと名称の前方一致で絞り込んで,会員一覧と購入最大価格を検索。
-- 絞り込み条件はそれぞれ値がnullじゃければ評価する。
select member.MEMBER_ID
     , member.MEMBER_NAME
...(以下変わらず)

で,同様にSql2Entityを実行します。

すると,指定されたプロパティの構成のBeanクラスが指定された名前で生成されます。そのクラスは「xxx.exdao.pmbean」配下に生成されます。そのクラスを先ほどの「手動で独自に定義したBean」に代わって利用することが可能です。

また,このParameterBeanのString型のプロパティは空文字「""」をnullとして扱います。

実は,先ほどの「手動で独自に定義したBean」では会員名称に空文字「""」を入れた場合,パラメータコメントの「/*IF pmb.memberName != null*/」がtrueになります。

実際の業務では,nullなのか空文字なのかを意識したくないことが多いかと思われます。プレゼンテーション層のフレームワークに依存もします。意外にこういった非常に細かい部分でのトラブルが結構現場では多いのです。

そのため,ParameterBeanにて空文字「""」を設定してもSQLのパラメータコメント上は,nullと扱われるようになっています(空白1文字以上「" "」は値として扱われます⁠⁠。無論,空文字をちゃんとした値として扱いたい場合もあると思いますので,生成されたParameterBeanのGapクラスの方でGetterをOverrideすることで空文字を活かすことも可能です。

しかし,個人的な見解になりますが,プログラム上またDB上において,空文字に意味を持たせる設計は何かとトラブルを呼びやすいためあまりおすすめはしません(筆者の経験上,そういった設計のシステムで細かいトラブルが多発したのを見たことがあります⁠⁠。

このSql2Entityで自動生成された引数のBeanをDBFluteでは「ParameterBean」と呼びます。

まとめ

複雑なSQLを実装するのに大活躍する外だしSQLの基本利用をご理解頂けましたでしょうか?

DBFluteはConditionBeanだけが「ウリ」なわけではありません。複雑なSQLはそのアプリケーションにとって肝になるロジックです。

そのSQLの実装はとても大事です。DBFluteはSql2Entityでより安全なOutsideSql(外だしSQL)の実装を提供します。

その他,DBFluteは用途に合わせた支援機能を備えています。

次回はそれら機能を紹介します。

著者プロフィール

久保雅彦(くぼまさひこ)

DBFluteメインコミッタ。主にオープン系の開発に従事。DB設計・DB周りの実装などを担当することが多い。