ぶりが提供するVIEWはOracleでインデックスが効いてない

ぶりが提供しているOracle用のDDLでは、TIMESTAMP型の扱いに誤りがあるため、VIEWでインデックスが効いてないものがあります。
VIEWの定義中、TIMESTAMP型であるprocessDateカラムをCURRENT_TIMESTAMPと比較しているところがありますが、CURRENT_TIMESTAMPはTIMESTAMP WITH TIMEZONE型です。
Oracleでは、TIMESTAMP型と、TIMESTAMP WITH TIMEZONE型は別の型です。暗黙の型変換が入るため、「processDate > CURRENT_TIMESTAMP」では、processDateに張ったインデックスが利用できません。
というわけで、ぶりをOracleで利用している場合は、CURRENT_TIMESTAMPを、TIMESTAMP型であるLOCALTIMESTAMPに修正する必要があります。この辺りの詳細は以下のページが参考になります。
CURRENT_DATE、CURRENT_TIMESTAMP - オラクル・Oracle SQL 関数リファレンス

あと、ぶりの権限管理を利用する場合は、BuriStateUserのdeleteDateカラムにインデックスを張りましょう。BuriPathDataUser、BuriPathHistoryDataUserビューのパフォーマンスが改善します。

DBFluteのぶり対応をカスタマイズ

jfluteさん向けメモ的なエントリ。
DBFluteでぶり対応を有効にすると、Entityに「BuriDef.パッケージ_プロセス_Status getStatus_パッケージ_プロセス()」というメソッドが追加されるけど、メソッドの中で getBuriPathData().getPathName() をしている。この「getBuriPathData()」を「getBuriPathHistoryDataUser()」にするのが今回の話。
BuriPathDataはParticipantProviderを使わない場合に利用するビューであって、ParticipantProviderを使ってアプリ側の実行ユーザー情報をBuriStateUserテーブルに入れている場合、そのユーザー情報も含めて取得するにはBuriPathDataUserビューを使わないといけない。
さらに、BuriPathDataUserには、INSERTDATE(その状態になったTimestamp)属性が無い。そのため、アプリの要件で「現在の状態と、その状態にしたユーザーと、その状態になったタイムスタンプ」を出そうとすると、BuriPathDataUserでも情報が足りない。この要件を満たすには、最新のBuriPathHistoryDataUserを取得しなければならない。
とりあえず、今回は必ずParticipantProviderを使うので、暫定でEntityにBuriPathHistoryDataUserへのadditionalForeignKeyを設定して、BaseEntity.vmのgetStatus_XXXで、getBuriPathDataしてるとこをgetBuriPathHistoryDataUserにしました。additionalForeignKey.dfpropはこんな感じに。

; FK_MEMBER_BuriPathHistoryDataUser = map:{
    ; localTableName  = MEMBER               ; foreignTableName  = BuriPathHistoryDataUser
    ; localColumnName = MEMBER_ID            ; foreignColumnName = pkeyNum
    ; fixedCondition  = $$foreignAlias$$.dataType = 'example.exentity.Member'
                        AND $$foreignAlias$$.processDate > CURRENT_TIMESTAMP
    ; fixedSuffix     = AsLatest
}

普通、BuriPathHistoryDataUserはEntityとN:1なんだけど、processDate > CURRENT_TIMESTAMP を入れることで1:1の関連にした。(CURRENT_DATEだとINSERTしてSELECTするテストコードで同じ秒の物を2件取得しちゃってコケる)
BaseEntity.vmはこんな感じ。

Index: dbflute/mydbflute/dbflute-0.9.4.1/templates/om/java/bsentity/BaseEntity.vm
===================================================================
--- dbflute/mydbflute/dbflute-0.9.4.1/templates/om/java/bsentity/BaseEntity.vm	(revision 1923)
+++ dbflute/mydbflute/dbflute-0.9.4.1/templates/om/java/bsentity/BaseEntity.vm	(working copy)
@@ -419,8 +419,8 @@
     //                                                                      ==============
 #foreach ($processName in $table.tableProcessForMethodNameList)
     public ${glBuriDef}.${processName}_Status getStatus_${processName}() {
-        if (getBuriPathData() == null) { return null; }
-        return ${glBuriDef}.${processName}_Status.codeOf(getBuriPathData().getPathName());
+        if (getBuriPathHistoryDataUserAsLatest() == null) { return null; }
+        return ${glBuriDef}.${processName}_Status.codeOf(getBuriPathHistoryDataUserAsLatest().getPathName());
     }
 #end
 #end

現在の状態を取得するとか、〜状態にあるエンティティを取得するだけならBuriPathDataで事足りるけど、それ以外のことをやろうとすると必ず他のビューが必要になるので、DBFluteが対応してるやつ以外にも自分でadditionalForeignKeyを追加する必要がありそう。ただBuriPathHistoryDataUserからMEMBERにadditionalForeignKey張ろうとしたら、pkeyNumがLong型、EntityのPKがInteger型で、コンパイルエラーになっちゃう。。。

Ubuntu 8.10 で Sun-Java を標準にする

https://help.ubuntu.com/community/Java

$ sudo apt-get install sun-java6-jdk
$ sudo update-java-alternatives -s java-6-sun

単に

$ sudo update-alternatives --config java

とすると、/etc/alternatives/java 以外のものが java-6-openjdk を指したまま残ってしまう。

ぶり祭り2008

先日ぶり祭り2008に参加してきました。どんな祭りだったかは ぶり祭 2008 - 豆無日記 が詳しいのでそちらで。しばらくBuriを調べてて、「これでワークフローエンジンとして耐えられるんだろうか?」と疑問に思っていたんだけれど、その疑問は解決?した。
ぶりはワークフローエンジンじゃない
そもそもワークフローエンジンじゃないんだから、その上でワークフローを組み立てるのが間違ってるよっていう話*1。だからスタロジ以外の人間が知らずにぶりに手を出すとハマるよ、と。で、じゃあぶりは何なのか?っていうと「エンティティステートマネージャー」ですよと。ここ重要です。
では具体的にぶりはどう料理したら美味しくいただけるのか。

  • エンティティとはS2Daoで言うところのEntityと同じレベルで、昔ITを使う前に人間が手で書いていた伝票のことをイメージすればよい。XPDLのフローを流れるものなのでXPDL上には登場しない。
  • ステートとはそのまま「状態」のこと。「申請中」とか「承認済み」っていうのがステートになる。XPDLではアクティビティ(箱)。
  • 「申請する」とか「承認する」というアクションは次のステートへの遷移(トランジション)になる。XPDLでは遷移。
  • ぶりのフローは、伝票ごとに1つ。申請書は申請フロー、発注書は発注フローを回る。1つのXPDLに業務フロー全体を書いてはいけない。

こうして見てみると、XPDLじゃなくてステートマシン図を書く感じがしてきた。*2
自分の中にあった「ワークフローとは」的な考えは、「申請」「承認」っていうのが箱で、それぞれの箱で伝票に対しての作業が終わったときに次の箱に遷移する、っていうものだった。だからぶりは使いづらいと感じてんだけど、使い方が間違っていたんだと納得。ぶりを使うときにはワークフロー的発想をどっかに追いやって、単に伝票の状態管理なんだって捉えて、業務フローをステートマシン図に落とし込むことを心がけよう。
ぶりを使う上で、実装段階で重要なのは「スタロジでは一回もBaoを使ったこと無い」ってこと。状態を進めるのはtoNextStatusで、状態の取得はBao経由ではなくSQLでとっちゃう。Bao経由しなくていいんだ、っていうのは収穫。ちょうどDBFluteS2Dao依存を弱めてきているし、パフォーマンス考えてもBao経由は無いと思ってたので良かった。*3後はBuriの内部テーブルの構造を都合のいいように変えられればいいかな。

後半はギョイゾーの紹介。ギョイゾーとぶり☆すたについては、みんな絶賛するんじゃないですかね。要件定義してたらFlashの画面ができてもう動きますとか、さらに安いですってきたら、発注側としたら絶対興味持つと思う。残念ながら自分は発注側の人間ではなく、中小規模案件を対象に仕事をしているので、正直感動してる余裕なんてなかったですけど。。

*1:もしかしたら羽生さんは「伝票の状態が人間の作業を通じて変わっていくことがワークフローなんだ」と言うのかもしれない。

*2:コード自動生成するためにXPDLなんだろうな。ステートマシン図からじゃ作図ツールに依存するし

*3:依然として状態変更にはS2Daoを使っているので、嫌ならtoNextStatusすら使わないで自前で実装してもいいかも

DBFlute-0.8.3と0.8.4は使っちゃダメ?

DBFlute-0.8.3(多分)から、自動生成されたコードがmaven(つまり素のJDK)でコンパイルできなくなっている。S2Dao依存を外して独自実装されたところで、Genericsの扱いにやられている模様。質の悪いことにEclipse上ではコンパイルできちゃってるので、コミットした後にHudson等のCIで初めて発覚するパターン。
修正されるまでは0.8.2を使うか、S2Daoを有効にしといたほうがよさげ。それともなんか環境が悪いのかなぁ…

S2Daoは枯れたと思ってたのに

1.0.49でAbstractIdentifierGeneratorのコンストラクタシグネチャが変更されたので、MS-Accessのオートナンバー用に作ったGenerator(IdentityIdentifierGeneratorを継承)がコンパイルエラーになってしまった。。。
DBFlutebasic-exampleも1.0.49にアップデートしたようなので、とりあえず最新にあわせておくか。