「めざましテレビ」

今日の早耳トレンドNo1」は Ray の石田香奈ちゃーん,お題は「暑い夏やっぱり食べたい! 人気のカレー」.
そうですか,香奈ちゃんが食レポですか.昨日のあさ美ちゃんと入れ替わったみたいですね.
ローテーションの改善に続いて固定的になっていた役割分担もシャッフルしようということでしょうか?
それなら,あさ美ちゃんのファッション担当も見ることが出来てよいかも.
でも,相沢紗世ちゃんのファッション担当はそのままでお願いしたい.
いや,出演回数が増えれば食レポとかやってくれても構わないか.


その紗世ちゃん,化粧品の CM に出演ですか.それはめでたい!
さらに,映画・ドラマの出演も決まっているとか.素晴らしい!
ところで化粧品ってどこのだろう?
おおっ,こんな所に情報が.
http://d.hatena.ne.jp/COOPER/20040727#p9
資生堂の新ブランドですか.いいなぁ.
どこかの化粧品ブランドさん,ぜひエビちゃんを CM に!


00:05 追記
さらに紗世ちゃん情報 via ファッションニュース
http://www.mainichi-msn.co.jp/geinou/wadai/news/20040727spn00m200011000c.html
9月創刊の雑誌「BOAO」でメインモデルを務めるそうです.すげー.
っことはやっぱり ViVi は卒業? だよね,きっと.

Hibernate 入門記 継承その2 table per subclass

継承の2回目です.
今回は,サブクラスごとに個別のテーブルにマッピングする方法について学習します.
サブクラスごとというか,継承階層のクラスごとといった方が適切かも.ルートクラスもテーブルにマップされるので.
ちなみに EJB 3.0(Early Draft) では,Joined Subclass Strategy に相当します.


このマッピングでは,継承階層のルートクラスがマッピングされるテーブルには,ルートクラスの永続プロパティに対応するカラムだけを持ちます.
そして,サブクラスごとに,そのサブクラス固有の永続プロパティを保持するカラムを持ったテーブルを用意します.
これらのテーブルを結合することで,永続オブジェクトの全てのプロパティが揃います.
テーブルを結合するにはキーが必要です.サブクラスがマッピングされるテーブルには,ルートクラスを参照する外部キーが必要となります.このマッピング方法の制限はこれくらいみたい.
前回の table per class hierarchy とは異なり,discriminator カラムは不要です.びっくり.これは,Hibernate の実装にとっては大変だとか.そーなんだぁ.とりあえず感謝しておこう.


テーブルの持ち方がわかったところで,マッピングについて学習します.
前回の table per class hierarchy と同様に,クラス階層全体を一つの

  • <class> 要素

で記述します.
ID プロパティの定義,プロパティおよび関連の定義の後に,各サブクラスのマッピングについて

  • <joined-subclass> 要素

で記述します.
5.1.14. joined-subclass」によると,こいつは次の属性を持っています.

name
クラス名を指定します.必須です.
proxy
遅延初期化する場合に指定するようですが,関連以外の遅延初期化はまだ学習していません.無念だ.
lazy
同上.
dynamic-update
すでにお馴染み.永続オブジェクトを更新した際に,変更のあったプロパティ (カラム) だけを更新するような SQL を発行する場合に true を指定します.デフォルトは false です.
dynamic-insert
上記の INSERT 版.

前回の <subclass> 要素とほぼ同じ.discriminator-value 属性がないだけです.よって,上のはコピペです.心より恥じる.
そして <joined-subclass> 要素の内容には,まず

  • <key> 要素

を記述します.
これは,ルートクラスがマッピングされるテーブルへの外部キーを指定するものです.属性などはこれまでに学習済み.
その後に,プロパティや関連のマッピングを記述します.
それに続けて,<joined-subclass> 要素も記述することが出来ます.深い深ーいクラス階層も記述できるのですね (こぴぺ).


さぁ,お試し開始です.
ネタは前回と同じで行きましょう.
まずはテーブル定義.

CREATE TABLE TALENT (
    ID INTEGER IDENTITY PRIMARY KEY,
    NAME VARCHAR
)

CREATE TABLE MODEL (
    ID INTEGER PRIMARY KEY,
    MAGAZINE VARCHAR
)

CREATE TABLE ACTRESS (
    ID INTEGER PRIMARY KEY,
    DRAMA VARCHAR
)

ルートクラスとサブクラスが二つで,合計三つのテーブルを用意しなくてはならないのですね.結構大変.
永続クラスについては,TalentModelActress とも前回と同じです.たぶん.
そしてタレントをルートとするクラス階層のマッピングファイル,study/Talent.hbm.xml です.

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"
>
<hibernate-mapping auto-import="false" package="study">
    <class name="Talent">
        <id name="id" access="field" unsaved-value="-1">
            <generator class="identity"/>
        </id>
        <property name="name" access="field"/>

        <joined-subclass name="Model">
            <key column="id"/>
            <property name="magazine" access="field"/>
        </joined-subclass>
 
        <joined-subclass name="Actress">
            <key column="id"/>
            <property name="drama" access="field"/>
        </joined-subclass>
    </class>
</hibernate-mapping>

そして実行用のクラスも前回と同じです.
それを実行!!!!

 onSave() : Yuri Ebihara
 Hibernate: insert into Talent (name, id) values (?, null)
 Hibernate: CALL IDENTITY()
 Hibernate: insert into Model (magazine, id) values (?, ?)
 onSave() : Akiko Yada
 Hibernate: insert into Talent (name, id) values (?, null)
 Hibernate: CALL IDENTITY()
 Hibernate: insert into Actress (drama, id) values (?, ?)
 onSave() : Kyoko Uchida
 Hibernate: insert into Talent (name, id) values (?, null)
 Hibernate: CALL IDENTITY()
 Hibernate: select talent0_.id as id, 
                 casewhen(talent0__1_.id is not null, 1,  
                     casewhen(talent0__2_.id is not null, 2,  
                         casewhen(talent0_.id is not null, 0, -1))) as clazz_, 
                 talent0_.name as name0_, talent0__1_.magazine as magazine1_, 
                 talent0__2_.drama as drama2_ 
             from Talent talent0_ 
                 left outer join Model talent0__1_ on talent0_.id=talent0__1_.id 
                 left outer join Actress talent0__2_ on talent0_.id=talent0__2_.id
 onLoad() : Yuri Ebihara
 onLoad() : Akiko Yada
 onLoad() : Kyoko Uchida
 Yuri Ebihara : CanCam
 Akiko Yada : My Little Chef
 Kyoko Uchida

またしても楽勝.いいねぇー (昔のアコム風)
にしても,この SELECT は... casewhen入れ子になった clazz_ の値で結果セットの行がどのクラスのインスタンスになるかを示す,discriminator カラムの役割を果たしているようですね.たしかに大変そう.よく頑張った!
でも,深い深ーい継承階層の場合の SQL を考えると... 怖ひぃ〜.


次回は残る一つのマッピング方式,table per concrete class へ進みます.

EJB3.0(Early Draft) 入門記 Chapter 7 その1

ちょっと間が開いてしまいましたが,今日から新しい章,
Chapter 7 Query Language
へ進みます.
Entity Bean のための問い合せ言語,いわゆる EJB QL ですね.かなり機能強化されているとのことです.
その項目一覧.

  • バルク更新と削除
  • 結合
  • GROUP BY と HAVING
  • プロジェクション
  • 副問い合せ

これらは,EJB 2.x の Entity Bean の finder/select メソッドからも使えるそうです.
EJB QL は,動的および静的な問い合せ双方でフルに使えて,それはパラメタライズできるとか.パラメタライズ... generics
なんて一瞬思ったのですが,そういうわけじゃなくて,問い合せにいわゆるバインド変数を使うことができるということみたい.心より恥じる.
そのバインド変数 (パラメタ) は名前を付けることができるそうです.
ということで,強化された機能の解説,始まり始まり〜.


7.1 Bulk Operations
バルク更新および削除.てっきり JDBC のバッチ更新的なものかと思いきや,全然違いました.心より恥じる.
サンプルが載っているので一番簡単なやつを引用.

DELETE
FROM Customer c
WHERE c.status = ‘inactive’
    AND c.orders IS EMPTY

ようするに,WHERE 句で条件にマッチしたエンティティをまとめて更新または削除できるよ,ということですか.エンティティというかもろに行ですな.
そうかぁ,今までは EntityBean のインスタンスを手に入れて更新/削除しなきゃいけなかったわけで,これだけでも大進歩ということですか.笑っちゃいますね.(^^;
なお,UPDATE または DELETE で指定することができる Entity Bean のクラスは一つだけとのこと.
それから,Entity Bean の状態を更新したトランザクションの中でバルク更新または削除すべきでないとのこと.ふむ.トランザクションがコミットされるまで,Entity Bean の状態がストレージ (RDBMS) に反映されるとは限らないということで,意図した結果にならないかもしれないということでしょうか.もしかして落とし穴候補?
ドキュメントには明示されていませんが,バルク削除が行われた場合,Entity Bean の ejbRemove() は呼び出されないものと予想されます.EJB3.0 ではコールバックメソッドがオプションなので,あまり問題ないと思いますけれど.


7.2 Joins
EJB 3.0 では,4種類の結合をサポートするようです.


7.2.1 Inner Join (General Case)
普通の内部結合.普通って何?
説明しよう.それは,関連をたどるのとは違うやつ全部だ.たぶん.きっと.じゃないかなぁ.
ともかく,WHERE 句で結合条件を指定すればいいらしいです.で,WEHERE 句を省略すると直積になるとか.ん? それを内部結合と呼ぶのか?
とりあえず例.

select c from customer c, employee e where c.hatsize = e.shoesize

たしかに普通だ.そのまんま普通だ.
が,なぜに FROM 句で結合条件を書くようにしないのだろう?

select c from customer c inner join employee e on c.hatsize = e.shoesize

ではだめなのかな?
結合の条件と選択の条件は明確に区別できた方がいいと思うけど.


7.2.2 Inner Join (Relationship Join)
こっちは普通じゃない内部結合.普通じゃないのは関連で結合するからだ.
ともかく例を見るべし.

SELECT c FROM Customer c JOIN c.orders WHERE c.status = 1

WHERE 句がついてますが,これは本題とは関係なさそう.大事なのは JOIN c.orders だけと思われ.
ここで c.orders は,1対多とか多対多とかの関連であると注釈されているのでしょう.そして,そこには外部キーのカラム名なんかが定義されていて,それを使って結合してくれるのでしょう.
そうか,普通の内部結合は WHERE 句で,関連による結合は FROM 句で,ということかな? そういう区別ならしょうがないか.許す.
ちなみに上の問い合せは,EJB 2.x の次の問い合せと同等だとか.

SELECT OBJECT(c) FROM Customer c, IN(c.orders) o WHERE c.status = 1

うん,この構文は馴染みにくいので,これは改善といえそう.
BNF を見ると,この 2.x の構文もまだまだ有効みたいですが.


7.2.3 Left Outer Join
そして外部結合.いわゆる外部結合.でも左だけ.右はない.フルもない.そして例もない... (;_;)
BNF によると,どうやら上の JOINLEFT または LEFT OUTER にすればいいだけらしい.

SELECT c FROM Customer c LEFT c.orders WHERE c.status = 1

みたいな.
外部結合の使い方の筆頭は,プリフェッチだとか.N+1 な問い合せを避けるためですね.それには,外部結合をフェッチ結合として使えとのこと.フェッチ結合って何?


7.2.4 Fetch Joins
説明しよう.フェッチ結合とは,問い合せの副作用として,関連をフェッチしてくれる結合である.たぶん.
まずは例.

SELECT DISTINCT c
FROM Customer c LEFT JOIN FETCH c.orders
WHERE c.address.state = ’CA’

この場合,問い合せ結果として戻されるのは Customer だけですが,問い合せの副作用として,選択された Customer に関連づけられた Ordre が初期化されます.らしいです.
Order が持つ関連をどうするか (フェッチするかしないかでしょう) は,Order クラスのメタデータにより指定できるようです.
なお,フェッチ結合の右側は,問い合せ結果として戻される Entity Bean (この場合は Customer) に関連づけれた Entity Bean でなければならないとのことです.
それから,フェッチ結合の右側の Entity Bean は,問い合せの他の場所 (SELECT 句やWHERE 句など) で使うことができないとのことです.
さらに,BNF によるとフェッチ結合は外部結合だけでなく,内部結合とも組み合わせることができるようです.


7.3 Projection
射影.リレーショナル用語ですね.情報処理試験くらいでしか耳にしない用語の気がしないでもない.(^^;
用語としては使わなくても,射影そのものは SQL では日常的に使いますね.SELECT 句にカラムを並べたてるアレのことなので.
射影は RDB/SQL ではごく普通に使うわけですが,O/Rマッピング的にはイマイチだということは「インピーダンス・ミスマッチ」や「Hibernate 入門記 コレクションその11 Lazy Initialization」でも書いたとおり.
にもかかわらず,EJB3.0 では射影をサポートするとのこと.
こんな感じ.

SELECT c.id, c.status
FROM Customer c JOIN c.orders o
WHERE o.count > 100

この結果は,java.lang.Object の配列として返されるらしいです.Hibernate の HQL と同じっぽい.
しかし... Object の配列なんかうれしくないやい!
大丈夫です,そんなあなたのためにステキな機能が用意されています.
その例.

SELECT new CustomerDetails(c.id, c.status, o.count)
FROM Customer c JOIN c.orders o
WHERE o.count > 100

このように問い合せをすると,CustomerDetails のリストが返されるのですが,この CustomerDetails は Entity Bean でなくても構わないのです.ほほーっ.いいかも.あっ,でも Hibernate でも同じことができるみたい♪


7.4 Group By, Having
まずは例.とにかく例.

SELECT c.status, avg(c.filledOrderCount), count(c)
FROM Customer c
GROUP BY c.status
HAVING s.status IN (1, 2)

ふむ.普通に使えるっぽい.
問い合せの結果は射影と同じで java.lang.Object の配列かな? きっとそうなんだろうなぁ.
集約関数の引数を除いて,SELECT 句に記述できるのは GROUP BY 句に記述されたプロパティのみとのこと.
油断してましたが,集約関数自体は EJB 2.x でもサポートされていたのですね.知らなかった... 心より恥じる.
でも,GROUP BY なしで集約関数とは中途半端な...


7.5 Subqueries
WHERE 句に副問い合せが書けるそうです.
ということで例.

SELECT goodCustomer
FROM Customer goodCustomer
WHERE goodCustomer.balance < (
    SELECT avg(c.balance) FROM Customer c)

もう一つの例.

SELECT DISTINCT emp
FROM Employee emp
WHERE EXISTS (
    SELECT spouseEmp
    FROM Employee spouseEmp
    WHERE spouseEmp = emp.spouse)

こっちの例は相関副問い合せですね.
ドキュメントに書いてあることはこれだけ.(^^;
例を載せて終わりとは... やってくれるなぁ.いいけど.


7.6 Support for Additional Functions
WHERE 句で使うことのできる関数が追加されているそうです.

  • UPPER
  • LOWER
  • TRIM
  • POSITION
  • CHARACTER_LENGTH
  • CHAR_LENGTH
  • BIT_LENGTH
  • CURRENT_TIME
  • CURRENT_DATE
  • CURRENT_TIMESTAMP

以上.


7.7 Polymorphism
EJB QL は,自動的にポリモーフィズムを扱ってくれるそうです.
FROM 句に書かれたクラスについては,その直接のインスタンスだけでなく,サブクラスのインスタンスも取ってきてくれるとのこと.
将来のドラフトでは,ポリモーフィズムを制限できるような問い合せの機能を追加する計画らしいです.


7.8 Named Parameters
名前付きのパラメータ.その例.

SELECT c
FROM Customer c
WHERE c.status = :stat

よかろう.


7.9 EJB 3.0 QL BNF
必要に応じて.


とうことで,駆け足でしたが 7 章終了です♪ やったね.
それにしても,結局のところ SQL なんですね.ひたすら SQL に近づいているだけじゃない?
SQL を書きたくない,書かせたくないという人達から CMP Entity Bean が期待されていたような気もするわけですが,そんな人達にとってこれは進歩なんでしょうか? ちょっと疑問.
自分は別に SQL 書いてもいいというか,仕事の方で使っている DAO なところは完全に SQL 主導なんで全然構いませんけれど...
なんにせよ,Hibernate 触っておけば怖くなさそう.ラッキー♪


ということで,次は 8 章,「Chapter 8 Enterprise Bean Context and Environment」へ進みます.

「ウォーターボーイズ2」

今週のえみちぃチェーック.なんと倍増だ!

  • 栞は? 栞は? 栞は?
  • 脱げてる,脱げてる,脱げてる

「脱げてる」は初回と同じ.やっぱり水着が脱げちゃったときだったんですね.
でも,今日のセリフは今まで際だっていた一本調子の不自然さがなくて,残念!!!!
…イヤべつに残念でもなんでもないのですが、


よし,インテル戦に間に合ったぞ.