Hibernate 入門記 コレクションその8 array で many-to-many
今回は配列です.配列はリストと同じく順序付きコレクションです.
配列のマッピングには,
<array>
要素
を使います.使い方はほとんど <list>
要素と同じです.
まず,属性については lazy
を指定することができないようです.代わりに次の属性が増えています.
element-class
- リファレンスに解説されていないのでよくわかりませんが,配列の要素の型でしょう.任意の属性なので,デフォルトはプロパティの要素の型になると思われます.
<array>
要素の内容は <list>
要素と全く同じで,<key>
要素,<index>
要素に続いて <element>
要素・<composite-element>
要素・<one-to-many>
要素・<many-to-many>
要素・<many-to-any>
要素のいずれかを記述します.いずれもすでに学習済みです.おっと,<many-to-any>
は常にスキップです.心より恥じる.
以上.相変わらず手抜きが続いているようにしか見えませんね... このシリーズを続ける意味はあるのだろうか? いや,一通り試すことに意義があるのだ.たぶん.きっと.
ということで一応お試しします.
基本的に前回のリストと同じでもいいわけですが,あまりにコードや結果のログが長くてごめんなさいだったので,今回はもっとシンプルにということで,いつものモデルと雑誌でいきます.
まずはテーブル.
CREATE TABLE MODEL ( ID INTEGER IDENTITY, NAME VARCHAR ) CREATE TABLE MAGAZINE ( ID INTEGER IDENTITY, NAME VARCHAR ) CREATE TABLE MODEL_MAGAZINE ( ID INTEGER IDENTITY, INDEX INTEGER, MODEL INTEGER, MAGAZINE INTEGER )
そしてモデルのクラス.
package study; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import net.sf.hibernate.CallbackException; import net.sf.hibernate.Lifecycle; import net.sf.hibernate.Session; public class Model implements Lifecycle { int id = -1; String name; Magazine[] magazine; public Model() { } public Model(String name) { this.name = name; } public String toString() { StringBuffer buf = new StringBuffer(); buf.append(name).append("["); for (int i = 0; magazine != null && i < magazine.length; ++i) { buf.append(magazine[i]).append(", "); } buf.setLength(buf.length() - 2); buf.append("]"); return new String(buf); } public void onLoad(Session s, Serializable id) { System.out.println("onLoad() : " + toString()); } public boolean onSave(Session s) throws CallbackException { System.out.println("onSave() : " + toString()); return false; } public boolean onUpdate(Session s) throws CallbackException { System.out.println("onUpdate() : " + toString()); return false; } public boolean onDelete(Session s) throws CallbackException { System.out.println("onDelete() : " + toString()); return false; } }
そしてモデルのマッピングファイル.
<?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="Model"> <id name="id" access="field" unsaved-value="-1"> <generator class="identity"/> </id> <property name="name" access="field"/> <array name="magazine" access="field" table="MODEL_MAGAZINE" cascade="all"> <key column="model"/> <index column="index"/> <many-to-many column="magazine" class="Magazine"/> </array> </class> </hibernate-mapping>
今回は多対多で初めて cascade
属性に "all"
を設定してみました.
次に雑誌のクラス.
package study; import java.io.Serializable; import net.sf.hibernate.CallbackException; import net.sf.hibernate.Lifecycle; import net.sf.hibernate.Session; public class Magazine implements Lifecycle { int id = -1; String name; public Magazine() { } public Magazine(String name) { this.name = name; } public String toString() { return name; } public void onLoad(Session s, Serializable id) { System.out.println("onLoad() : " + toString()); } public boolean onSave(Session s) throws CallbackException { System.out.println("onSave() : " + toString()); return false; } public boolean onUpdate(Session s) throws CallbackException { System.out.println("onUpdate() : " + toString()); return false; } public boolean onDelete(Session s) throws CallbackException { System.out.println("onDelete() : " + toString()); return false; } }
そして雑誌のマッピングファイル.
<?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="Magazine"> <id name="id" access="field" unsaved-value="-1"> <generator class="identity"/> </id> <property name="name" access="field"/> </class> </hibernate-mapping>
二つのマッピングファイルを hibernate.cfg.xml
に記述します.
そして実行用のクラス.
package study; import java.util.Iterator; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.cfg.Configuration; public class Main { public static void main(String[] args) { try { Configuration config = new Configuration(); SessionFactory factory = config.configure().buildSessionFactory(); Session session = factory.openSession(); Magazine cancam = new Magazine("CanCam"); Magazine vivi = new Magazine("ViVI"); Magazine classy = new Magazine("CLASSY"); Model yuri = new Model("Yuri Ebihara"); yuri.magazine = new Magazine[1]; yuri.magazine[0] = cancam; session.save(yuri); Model sayo = new Model("Sayo Aizawa"); sayo.magazine = new Magazine[2]; sayo.magazine[0] = vivi; sayo.magazine[1] = classy; session.save(sayo); Model asami = new Model("Asami Usuda"); asami.magazine = new Magazine[1]; asami.magazine[0] = cancam; session.save(asami); session.flush(); session = factory.openSession(); Iterator it = session.find("from study.Model").iterator(); while (it.hasNext()) { System.out.println(it.next()); } } catch (Throwable e) { e.printStackTrace(); } } }
明示的に Session#save(Object)
を呼び出しているのはモデルだけです.
こいつを実行!
onSave() : Yuri Ebihara[CanCam] Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : CanCam Hibernate: insert into Magazine (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : Sayo Aizawa[ViVI, CLASSY] Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : ViVI Hibernate: insert into Magazine (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : CLASSY Hibernate: insert into Magazine (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : Asami Usuda[CanCam] Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() Hibernate: insert into MODEL_MAGAZINE (model, index, magazine) values (?, ?, ?) Hibernate: select model0_.id as id, model0_.name as name from Model model0_ Hibernate: select magazine0_.magazine as magazine__, magazine0_.model as model__, magazine0_.index as index__ from MODEL_MAGAZINE magazine0_ where magazine0_.model=? Hibernate: select magazine0_.id as id0_, magazine0_.name as name0_ from Magazine magazine0_ where magazine0_.id=? onLoad() : CanCam onLoad() : Yuri Ebihara[CanCam] Hibernate: select magazine0_.magazine as magazine__, magazine0_.model as model__, magazine0_.index as index__ from MODEL_MAGAZINE magazine0_ where magazine0_.model=? Hibernate: select magazine0_.id as id0_, magazine0_.name as name0_ from Magazine magazine0_ where magazine0_.id=? onLoad() : ViVI Hibernate: select magazine0_.id as id0_, magazine0_.name as name0_ from Magazine magazine0_ where magazine0_.id=? onLoad() : CLASSY onLoad() : Sayo Aizawa[ViVI, CLASSY] Hibernate: select magazine0_.magazine as magazine__, magazine0_.model as model__, magazine0_.index as index__ from MODEL_MAGAZINE magazine0_ where magazine0_.model=? onLoad() : Asami Usuda[CanCam] Yuri Ebihara[CanCam] Sayo Aizawa[ViVI, CLASSY] Asami Usuda[CanCam]
ふむ.特にどうということもなく,いつもと同じっぽい.
カスケード周りが気になったのであれこれ試してみたのですが,カスケード削除の方はあまりうまくいっていないような?
参照されなくなった雑誌の削除まではしてくれませんでした.まぁそんなもんだろうと予想はしていましたが.
これで配列も終了ということにします.残すところはバッグの二つのみ.今週中にはコレクションシリーズを卒業できるかな? いや,金曜日は EbiYuri デーだから難しいか? 心より恥じる.