Hibernate 入門記 コレクションその7 list で element
今回はリストです.このリストは java.util.List
と同じような意味で,順序付きコレクションのことです.
リストのマッピングを指定するには,
<list>
要素
を使います.
こいつの使い方は,限りなく <map>
要素と近いようです.
まず属性については,order-by
属性が使えないことが <map>
要素と異なります.順序は後述の <index>
要素で指定するためです.そのほかの属性は <map>
要素と同じです.
内容については,最初に
<key>
要素
を記述します.これは <set>
要素や <map>
要素と同じで,こっち(この定義をしている永続クラス)への外部キーを指定するために使います.
次にインデックスを保持するカラムの情報を
<index>
要素
で指定します.<map>
要素と異なり,<composite-index>
要素や <index-many-to-many>
要素を指定することはできません.
<index>
要素の属性として次のものを指定します.
column
- インデックスとなるカラムの名前を指定します.
type
- インデックスとなるカラムの型を指定します.デフォルトは
integer
です.
ここで指定するカラムの値は,0から始まる数値でなければならないとか.ふむ.リストってそういうものなんですね.てっきり結果セットの順番で java.util.List
につっこんでくれるのかと思いました.そうか,それだと INSERT/UPDATE がうまくできないのか.インデックスが途中で飛ぶような場合はどうなるんだろう? うーみゅ,お試ししますか.
ともあれ,最後に関連先のマッピングを次のいずれかで指定します.
<element>
要素<composite-element>
要素<one-to-many>
要素<many-to-many>
要素<many-to-any>
要素
これは <set>
要素や <map>
要素と同じですね.
以上です.マップとほとんど変わらないのでラクチンっぽい.
ということでお試しです.
順序付きかぁ.エビちゃんをランク付けするってのはちょっとなんだかなぁ.
ということで,「早耳トレンドNo1」の月別登場回数でランキングしてみましょう.
まずはテーブル定義.
CREATE TABLE HAYAMIMI ( ID INTEGER IDENTITY, MONTH INTEGER ) CREATE TABLE MODEL ( ID INTEGER IDENTITY, NAME VARCHAR ) CREATE TABLE RANKING ( ID INTEGER IDENTITY, HAYAMIMI INTEGER, RANK INTEGER, MODEL INTEGER )
そして「早耳」の永続クラス.
package study; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import net.sf.hibernate.CallbackException; import net.sf.hibernate.Lifecycle; import net.sf.hibernate.Session; public class Hayamimi implements Lifecycle { int id = -1; int month; List model; public Hayamimi() { } public Hayamimi(int month) { this.month = month; this.model = new ArrayList(); } public String toString() { return "早耳トレンドNo1 " + month + "月 " + model; } 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; } }
「早耳」のマッピングファイル,study/Hayamimi.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="Hayamimi"> <id name="id" access="field" unsaved-value="-1"> <generator class="identity"/> </id> <property name="month" access="field"/> <list name="model" access="field" table="ranking"> <key column="hayamimi"/> <index column="rank"/> <many-to-many column="model" class="Model"/> </list> </class> </hibernate-mapping>
そしてモデルの永続クラス.
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; public Model() { } public Model(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; } }
モデルのマッピングファイル,study/Model.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="Model"> <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(); Model asami = new Model("あさ美"); session.save(asami); Model anne = new Model("杏"); session.save(anne); Model kana = new Model("香奈"); session.save(kana); Model sayo = new Model("紗世"); session.save(sayo); Model jun = new Model("潤"); session.save(jun); Model rosa = new Model("ローサ"); session.save(rosa); Hayamimi april = new Hayamimi(4); april.model.add(kana); april.model.add(asami); april.model.add(jun); april.model.add(rosa); april.model.add(anne); april.model.add(sayo); session.save(april); Hayamimi may = new Hayamimi(5); may.model.add(asami); may.model.add(kana); may.model.add(anne); may.model.add(jun); may.model.add(rosa); may.model.add(sayo); session.save(may); Hayamimi june = new Hayamimi(6); june.model.add(asami); june.model.add(kana); june.model.add(anne); june.model.add(jun); june.model.add(sayo); june.model.add(rosa); session.save(june); session.flush(); session = factory.openSession(); Iterator it = session.find("from study.Hayamimi").iterator(); while (it.hasNext()) { System.out.println(it.next()); } session = factory.openSession(); Hayamimi hayamimi = (Hayamimi) session.find("from study.Hayamimi hayamimi where hayamimi.month = 4").iterator().next(); hayamimi.model.remove(0); session.update(hayamimi); session.flush(); session = factory.openSession(); it = session.find("from study.Hayamimi").iterator(); while (it.hasNext()) { System.out.println(it.next()); } } catch (Throwable e) { e.printStackTrace(); } } }
最初にしっかりとデータを作って,後から4月のランク1位を取り除いています.どうなりますやら.
こいつを実行!!
onSave() : あさ美 Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 杏 Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 香奈 Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 紗世 Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 潤 Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : ローサ Hibernate: insert into Model (name, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 早耳トレンドNo1 4月 [香奈, あさ美, 潤, ローサ, 杏, 紗世] Hibernate: insert into Hayamimi (month, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 早耳トレンドNo1 5月 [あさ美, 香奈, 杏, 潤, ローサ, 紗世] Hibernate: insert into Hayamimi (month, id) values (?, null) Hibernate: CALL IDENTITY() onSave() : 早耳トレンドNo1 6月 [あさ美, 香奈, 杏, 潤, 紗世, ローサ] Hibernate: insert into Hayamimi (month, id) values (?, null) Hibernate: CALL IDENTITY() Hibernate: insert into ranking (hayamimi, rank, model) values (?, ?, ?) Hibernate: select hayamimi0_.id as id, hayamimi0_.month as month from Hayamimi hayamimi0_ Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 香奈 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : あさ美 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 潤 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : ローサ Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 杏 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 紗世 onLoad() : 早耳トレンドNo1 4月 [香奈, あさ美, 潤, ローサ, 杏, 紗世] Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? onLoad() : 早耳トレンドNo1 5月 [あさ美, 香奈, 杏, 潤, ローサ, 紗世] Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? onLoad() : 早耳トレンドNo1 6月 [あさ美, 香奈, 杏, 潤, 紗世, ローサ] 早耳トレンドNo1 4月 [香奈, あさ美, 潤, ローサ, 杏, 紗世] 早耳トレンドNo1 5月 [あさ美, 香奈, 杏, 潤, ローサ, 紗世] 早耳トレンドNo1 6月 [あさ美, 香奈, 杏, 潤, 紗世, ローサ] Hibernate: select hayamimi0_.id as id, hayamimi0_.month as month from Hayamimi hayamimi0_ where (hayamimi0_.month=4 ) Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 香奈 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : あさ美 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 潤 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : ローサ Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 杏 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 紗世 onLoad() : 早耳トレンドNo1 4月 [香奈, あさ美, 潤, ローサ, 杏, 紗世] Hibernate: delete from ranking where hayamimi=? and rank=? Hibernate: update ranking set model=? where hayamimi=? and rank=? Hibernate: select hayamimi0_.id as id, hayamimi0_.month as month from Hayamimi hayamimi0_ Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : あさ美 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 潤 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : ローサ Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 杏 Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 紗世 onLoad() : 早耳トレンドNo1 4月 [あさ美, 潤, ローサ, 杏, 紗世] Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? Hibernate: select model0_.id as id0_, model0_.name as name0_ from Model model0_ where model0_.id=? onLoad() : 香奈 onLoad() : 早耳トレンドNo1 5月 [あさ美, 香奈, 杏, 潤, ローサ, 紗世] Hibernate: select model0_.model as model__, model0_.hayamimi as hayamimi__, model0_.rank as rank__ from ranking model0_ where model0_.hayamimi=? onLoad() : 早耳トレンドNo1 6月 [あさ美, 香奈, 杏, 潤, 紗世, ローサ] 早耳トレンドNo1 4月 [あさ美, 潤, ローサ, 杏, 紗世] 早耳トレンドNo1 5月 [あさ美, 香奈, 杏, 潤, ローサ, 紗世] 早耳トレンドNo1 6月 [あさ美, 香奈, 杏, 潤, 紗世, ローサ]
ふむふむ.
関連を取り除くと,関連テーブルに対する DELETE と UPDATE が実行されるのですね(太字になっているところ).
ちなみに,順序づけられた関連レコードの最後(ランクが一番大きい行)が削除されて,1番目から最後の1つ前(新しい最後)までの行の MODEL カラムが更新されています.
この状況を見ると,順序が頻繁に変わるような場合には使いたくない感じですね.リストの後ろに追加するだけの場合は悪くないかも.
こんなもんでリストは終了.次回は配列に挑みます.