DBFlute -- DBFlute-0.5.5-RC2 を公開しました!


DBFlute内のS2DaoのVersionの最新Default設定が1.0.46になっています。
1.0.45をお使いの方は、torque.s2daoVersion = 1.0.45 を指定して下さい。

 {New}
 [DBFLUTE-140] {Java}: BehaviorにてIdentityとSequenceを利用側から区別無いようにするモードを設ける。
 [DBFLUTE-139] {Java}: ConditionBeanにおいて、設定次第でBind変数をリテラルに変更できるようにする。
 [DBFLUTE-137] {Java}: S2Daoの拡張部分でAnnotationReaderFactoryImplを利用する。
 [DBFLUTE-136] {Java}: S2DaoのSqlFileEncoding(外だしSQLのEncoding指定)を指定可能にする。
 [DBFLUTE-135] {Java}: EntityのModifiedPropertiesの登録を「同じ値のときはしない動き(null以外)」をOptionで実現する。
 [DBFLUTE-133] {Java}: 1件を期待する検索の場合の1件CheckをResultSet時点で行う。
 [DBFLUTE-132] {Java}: アプリケーション独自のDaoMetaDataFactoryを利用可能にする。
 [DBFLUTE-130] {Java}: FLATなデータを階層構造に展開するModuleを作成する。{枝分かれ展開可能}
 {Bug}
 [DBFLUTE-134] {Java}: S2Dao-1.0.39以前にてコンパイルエラーが発生してしまう。
 [DBFLUTE-131] {Java}: ConditionQueryにてPrimaryKeyが無くてForeignKeyのあるTableの場合にImport文が足りない。

たくさん、あり過ぎて紹介しきれない。。。

基本的には細かいのが多いです。
→ [DBFLUTE-136]/[DBFLUTE-137]/[DBFLUTE-133]とか

また、大きくてもとてもレアな状況で利用する機能とか
→ [DBFLUTE-130]


意外なものは、[DBFLUTE-133]です。
一件であること(二件以上でないこと)のチェックを戻り値のListの件数で
判断していたのを、ResultSetのLoopで行うようにしました。
(Behavior.selectEntity()の話です)
何がよくなったかというと、selectEntity()の条件を間違えていて、
二件どころか100万件Selectしちゃったときに、
チェックの前にResultSetのLoopで延々帰ってこない事態を防ぎます。
ほとんど、その恩恵に預かることはないとは思いますが、
開発用DBではデータ不備でその間違った条件が判明しないまま、
結合用DBで試して100万件Selectしちゃって、Tomcat落ちるは
周りの人のテスト落ちるは原因がすぐにつかめないやら。。。
という事態が万が一でも起きて欲しくないと願っての対応です。
(近い状況が実際にあったのです。周りのテストが止まって大変!)


[DBFLUTE-130]は、とても説明に時間が掛かってしまいます。
申し訳ありませんが、興味のある方は、自動生成されたクラスで
xxx.allcommon.dbmeta.hierarchy.HierarchyArrangerをご覧下さい。
一言で言うと、
「Sql2Entityのフラットな結果をテーブル階層構造に展開」※枝分かれもOK
BehaviorのLoadを使っても辛いと思うぐらいの「たくさんの関連テーブル」を
一気に取得したい(かつ、階層構造で)場合に有効です。
普通のDB構造や画面検索ではあまり考えられませんが、「時たま」必要になります。

実装サンプルをはりつけます。

public java.util.List selectListBookFromHierarchyFlat() {
// Search
final List hierarchyFlatBookList = getMyDao().selectListHierarchyFlatBook();

// Create hierarchy request
final HierarchyBasicRequest request = createHierarchyBasicRequest(hierarchyFlatBookList);

// Define source dbmeta
final HierarchyFlatBookDbm sourceDbm = HierarchyFlatBookDbm.getInstance();

// Register column [primaryBookId]
request.src(sourceDbm.columnPrimaryBookId()).dst().columnBookId();

// Register column [attributeBookName]
request.src(sourceDbm.columnAttributeBookName()).dst().columnBookName();

// Register column [primaryAuthorId]
request.src(sourceDbm.columnPrimaryAuthorId()).dst().foreignAuthor().columnAuthorId();

// Register column [attributeAuthorName]
request.src(sourceDbm.columnAttributeAuthorName()).dst().foreignAuthor().columnAuthorName();

// Register column [primaryCollectionId]
request.src(sourceDbm.columnPrimaryCollectionId());
request.dst().refererCollectionList().columnCollectionId();

// Register column [attributeArrivalDate]
request.src(sourceDbm.columnPrimaryCollectionId());
request.dst().refererCollectionList().columnArrivalDate();

// Arrange hierarchy
return arrangeHierarchy(request);
}

Sql2Entityを使った外だしSQLのDaoメソッドを
BehaviorのSubClassにて呼び出しているところです。
戻り値のjava.util.Listは、指定された通りに階層構造の
Instanceを保持します。
(親テーブルやら、子テーブルやら、子の親テーブルやら、親の子の子の親...)

= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ポイントは、列のMapping指定も関連指定も全て「タイプセーフ」であることです。
DB変更などの際にすぐに検知できます。
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =

大事なこと忘れてました。SQLはこんな感じです。
親結合だけでなく、子供もleft outerで結合してます。
なので、結果一覧は、BOOK部分が重複して取得されます。
枝分かれの子供をleft outerするとさらに重複しまくります。
それを階層構造に展開するのです。


--#HierarchyFlatBook#

select book.BOOK_ID as PRIMARY_BOOK_ID
, book.BOOK_NAME as ATTRIBUTE_BOOK_NAME
, author.AUTHOR_ID as PRIMARY_AUTHOR_ID
, author.AUTHOR_NAME as ATTRIBUTE_AUTHOR_NAME
, collection.COLLECTION_ID as PRIMARY_COLLECTION_ID
, collection.ARRIVAL_DATE as ATTRIBUTE_ARRIVAL_DATE
, collectionStatus.COLLECTION_ID as PRIMARY_COLLECTION_ID
, collectionStatus.COLLECTION_STATUS_CODE as ATTRIBUTE_COLLECTION_STATUS_CODE
, collectionStatus.COLLECTION_STATUS_CODE as ATTRIBUTE_COLLECTION_STATUS_CODE
, collectionStatusLookup.COLLECTION_STATUS_CODE as PRIMARY_COLLECTION_STATUS_CODE
, collectionStatusLookup.COLLECTION_STATUS_NAME as ATTRIBUTE_COLLECTION_STATUS_NAME
from BOOK book
left outer join AUTHOR author on book.AUTHOR_ID = author.AUTHOR_ID
left outer join COLLECTION collection on book.BOOK_ID = collection.BOOK_ID
left outer join COLLECTION_STATUS collectionStatus on collection.COLLECTION_ID = collectionStatus.COLLECTION_ID
left outer join COLLECTION_STATUS_LOOKUP collectionStatusLookup on collectionStatus.COLLECTION_STATUS_CODE = collectionStatusLookup.COLLECTION_STATUS_CODE
;