アプリごとの外だしSQL

外だしSQLのゆくえは?

例えば、以下のような複数プロジェクト構成の開発があるとします。

dblib
DBFluteの自動生成クラス、DB周りのロジック (ライブラリ扱い)
web1
コンシューマ向けのWEBサイト
web2
コンシューマ向けの携帯用WEBサイト (別会社に発注)
web3
管理用WEBサイト (海外に発注)
batch
バッチプロジェクト
web4
さらに別のコンシューマ向けのWEBサイト (海外に発注)

外だしSQLは、デフォルト設定ではGenerateタスクで自動生成されるテーブル対応のクラスと同じプロジェクト内で管理されます。 この例の場合は、dblib プロジェクトに外だしSQLが配置され、そこから自動生成されるクラス(CustomizeEntity や ParameterBean など)もそこに生成されることが前提となっています。

しかし、このような複数のアプリケーションがある構成の場合、 ある特定のアプリしか利用しない外だしSQLを共通のプロジェクトに配置するというちょっと違和感のある状態になる可能性があります。 また、そもそも組織上の問題やインフラ的な制約でライブラリプロジェクトへの修正が許されない、もしくは、あまりそうすべきではないという状況もあるでしょう。

もちろん、DBFluteは ConditionBean を提供しているため、外だしSQLが山のように大量に作成されることはあまりなく、10 から 20 程度の外だしSQLであれば、一元管理という意味合いも兼ねてライブラリプロジェクトの中で作成するやり方で十分なことが多いでしょう。 外だしSQLは、アプリケーションの肝となる複雑で神経質にならなければならないロジックになりがちで、ConditionBean よりも一元管理の利点の比重が高くなります。 とはいえ、それを超えるような量の外だしSQLが想定されるようなプロジェクトであれば、 やはりアプリケーションごとに外だしSQLを管理したいと考えるものです。

アプリ内に外だしSQLを配置

そこで、DBFluteでは外だしSQLをアプリごとに管理できるような仕組みがあります。 outsideSqlDefinitionMap.dfprop の applicationOutsideSqlMap にて、web1 や web2 への(DBFluteクライアントからの相対)パスを定義することで利用できます。@since 0.9.8.2

e.g. web1とweb2プロジェクトを対象に (ディレクトリはデフォルト設定) @outsideSqlDefinitionMap.dfprop
; applicationOutsideSqlMap = map:{
    ; ../../web1 = map:{
        #; sqlDirectory = src/main/resources
        #; sql2EntityOutputDirectory = src/main/java
    }
    ; ../../web2 = map:{
        #; sqlDirectory = src/main/resources
        #; sql2EntityOutputDirectory = src/main/java
    }
}

これを アプリケーション外だしSQL(ApplicationOutsideSql) と呼びます。

例えば、web1 のプロジェクト内に外だしSQLを作成し、Sql2Entityを実行するとその外だしSQLに対応する CustomizeEntity や ParameterBean が、同じ web1 のプロジェクト内に自動生成されます。当然、それらクラスは web2 からは参照できない形となりますし、ライブラリプロジェクトに対する修正など一切が入りません。

一方で、本当に web1 や web2 などの複数のアプリから再利用される外だしSQLは、今まで通りのやり方で管理することも同時に可能です。 再利用される外だしSQLとアプリ固有の外だしSQLを明確に分けて管理することができます。

e.g. ApplicationOutsideSqlの自動生成クラス(と外だしSQLの配置) {MEMBER} @Directory
dblib // DB関連のライブラリプロジェクト
 |-src/main/java
 |  |-com.example.dblib.dbflute.bsbhv
 |     |-BsMemberBhv.java
 |  |-com.example.dblib.dbflute.exbhv
 |     |-MemberBhv.java
 |-src/main/resource
    |-com.example.dblib.dbflute.exbhv
       |-MemberBhv_selectCommon.sql // システム全体で共通の外だしSQL定義
web1
 |-src/main/java
 |  |-com.example.dblib.dbflute.bsentity.customize
 |  |  |-BsAppOriginal.java // アプリ固有のCustomizeEntity(Bsクラス)
 |  |-com.example.dblib.dbflute.exentity.customize
 |  |  |-AppOriginal.java // アプリ固有のCustomizeEntity(Exクラス)
 |-src/main/resources
    |-com.example.dblib.dbflute.exbhv
       |-MemberBhv_selectAppOriginal.sql // アプリ固有の外だしSQL
web2
 |-src/main/java
 |  |-com.example.dblib.dbflute.bsentity.customize
 |  |  |-BsAppOriginal.java // アプリ固有のCustomizeEntity(Bsクラス)
 |  |-com.example.dblib.dbflute.exentity.customize
 |  |  |-AppOriginal.java // アプリ固有のCustomizeEntity(Exクラス)
 |-src/main/resources
    |-com.example.dblib.dbflute.exbhv
       |-MemberBhv_selectAppOriginal.sql // アプリ固有の外だしSQL

また、dblib プロジェクトの外だしSQLに加えて web1 や web2 の外だしSQLも同時に OutsideSqlTest の対象にもなりますし、SchemaHTML でも双方の外だしSQLが表示されるので、一元管理という視点のアプローチも失ってはいません。

細かい補足

TypedParameterBean の利用がお奨め

BehaviorのBsクラスに定義される BehaviorQueryPath(static final の定義) は、アプリ固有の外だしSQLのものは含まれません。 この機能のコンセプトを考慮すると、Sql2Entityの実行でライブラリプロジェクトのクラスに修正が入るようなことは避けた方が良いと考えられています。 よって、外だしSQLは基本的に TypedParameterBean 経由で呼び出すことが強く推奨されます。

※いずれにせよ、TypedParameterBean は推奨されています

アプリごとのBehaviorは?

このアプリケーション外だしSQLの利点を包含し、さらにはアプリケーションギャップにも対応できる、 アプリごとのBehavior(ApplicationBehavior)という機能が別途独立して存在します。 ですが、そちらは若干設定や仕組みが大げさになるため、 一部のメリットは割り切ってもっと気軽に利用できるアプローチがこのアプリケーション外だしSQLと言えます。

Exampleのススメ

dbflute-guice-example と dbflute-sqlap-example にて、実際にアプリごとの外だしSQLを利用しています。

DBFlute Example - 特定環境