Hibernate入門記 マッピング定義その4 property要素
順番だと次は「5.1.6. discriminator」なのですが,これは「8. Inheritance Mapping」で,その後の「5.1.7. version (optional)」および「5.1.8. timestamp (optional)」は「10. Transactions And Concurrency」で,それぞれ解説されているようなので無視しちゃいます.心より恥じる.
次行きましょう,次!(エビちゃん風)
ということで,今回は「5.1.9. property」へ進みます.毎回おなじみの
<property>
要素
です.永続クラスのプロパティとテーブル(カラム)のマッピングを指定するものですね.
こやつの属性をザクッと.
name
- 唯一の必須属性で,プロパティの名前を指定します.先頭文字は小文字にしろとのことです."
URI
" みたいなプロパティはどうするんだろう? JavaBeans的にはプロパティ名も "URI
" だったはずですが... column
- テーブルのカラム名を指定します.省略すると
name
属性の値が使われます. type
- プロパティの型を指定します.オプションです.
update/insert
- UPDATE/INSERTのSQL文中にこのプロパティを含めるかどうかを指定します.導出項目などの非永続的なプロパティの場合に
false
を指定する,と.省略するとtrue
です. formula
- 導出項目の場合にその値を求めるSQLの式を指定します.
access
- Hibernateが永続クラスのプロパティにアクセスする方法を指定します.デフォルトは
"property"
で,setter/getter を通してプロパティにアクセスします."field"
を指定すると,フィールドに直接アクセスします.永続クラスに setter を用意したくない場合に使えますね.net.sf.hibernate.property.PropertyAccessor
をimplements
したクラスを指定することもできます.どんな場合に必要になるのかイメージしにくいですが.
といった感じです.
そうか,<id>
要素にも出てきた access
属性はそういう意味だったのか... ここまで見に来ればよかった.無念だ.
<id>
要素でよくわからなかったもう一つの属性,type
属性についても,ちょっとだけまとまった説明がありました.なのですが,どうやら「5.2. Hibernate Types」でさらに詳しく解説されているようなので,ここでは無視しておきます.心より恥じる.
あれ? これでもう <property>
要素は終わりですか? あっさりしすぎかなぁ.まいっか.
ということで実験コーナーです.今回は導出項目に決まっています.導出項目といえば単価×数量というのがお約束です.あう,石を投げないでぇ〜.
石を投げられたので,年齢にしましょう.ということでモデルさんのテーブルを作成します.当然ながら,ドメインモデルとかMVCとかのモデルではなく,雑誌モデルのモデルです.
CREATE TABLE MODEL ( ID INTEGER IDENTITY, FIRSTNAME VARCHAR, LASTNAME VARCHAR, BIRTHDAY DATE )
え? 石を投げられたからじゃなくてモデルが好きなだけだろって? 違いますよぉ,そんな不謹慎な理由でサンプル作ったりしませんよぉ.あうあう.
次行きましょう,次!(エビちゃん風)
次は 永続クラスです.今回はせっかくなので,フィールドの可視性をパッケージにして getter/setter を作らないことにしました.全然意味はないのですが,とにかく試したかったのです.
package study; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date; import net.sf.hibernate.CallbackException; import net.sf.hibernate.Lifecycle; import net.sf.hibernate.Session; public class Model implements Lifecycle { private static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd"); int id = -1; String firstName; String lastName; Date birthday; int age; public String toString() { synchronized (formatter) { return firstName + " " + lastName + ", " + formatter.format(birthday) + "(" + age + ")"; } } 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; } }
getter/setter がない分よけいなコードが少なくて日記的にはよいかも.
ちなみにこういう場合の Date
って,java.util
のでいいのでしょうか? それとも java.sql
のを使うべきでしょうか? 制約がなければ java.util
の方で済ませたいところです.ということでまずは java.util
にしておきました.
次にマッピングファイル.
<?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="firstName" access="field"/> <property name="lastName" access="field"/> <property name="birthday" access="field"/> <property name="age" access="field" update="false" insert="false" formula="year(curdate()) - year(birthday) - casewhen(month(curdate()) * 100 + dayofmonth(curdate()) < month(birthday) * 100 + dayofmonth(birthday), 1, 0)" /> </class> </hibernate-mapping>
年齢を求めるところがひどく見苦しいですね... すっきりした求め方がわからなかったので苦し紛れです.心より恥じる.
次行きましょう,次!(エビちゃん風)
最近ご無沙汰の hibernate.cfg.xml
で今までの Customer.hbm.cfg
に替えて Model.hbm.xml
をマッピングファイルとして指定します.
<?xml version="1.0"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-2.0.dtd" > <hibernate-configuration> <session-factory> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost:9001</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <property name="dialect">net.sf.hibernate.dialect.HSQLDialect</property> <property name="show_sql">true</property> <mapping resource="study/Model.hbm.xml"/> </session-factory> </hibernate-configuration>
最後に実行用のクラス.相変わらず後処理とかしてなくて心より恥じるです.
package study; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; 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 yuri = new Model(); yuri.firstName = "Yuri"; yuri.lastName = "Ebihara"; yuri.birthday = new GregorianCalendar(1979, 10 - 1, 3).getTime(); session.save(yuri); Model yu = new Model(); yu.firstName = "Yu"; yu.lastName = "Yamada"; yu.birthday = new GregorianCalendar(1984, 7 - 1, 5).getTime(); session.save(yu); Model moe = new Model(); moe.firstName = "Moe"; moe.lastName = "Oshikiri"; moe.birthday = new GregorianCalendar(1979, 12 - 1, 29).getTime(); session.save(moe); session.flush(); session = factory.openSession(); List models = session.find("from study.Model"); Iterator it = models.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } catch (Throwable e) { e.printStackTrace(); } } }
工夫なさ過ぎでINSETしてSELECTするだけなんですが,いいんですっ!
これを実行!!!!
onSave() : Yuri Ebihara, 1979/10/03(0) Hibernate: insert into MODEL (firstName, lastName, birthday, id) values (?, ?, ?, null) Hibernate: CALL IDENTITY() onSave() : Yu Yamada, 1984/07/05(0) Hibernate: insert into MODEL (firstName, lastName, birthday, id) values (?, ?, ?, null) Hibernate: CALL IDENTITY() onSave() : Moe Oshikiri, 1979/12/29(0) Hibernate: insert into MODEL (firstName, lastName, birthday, id) values (?, ?, ?, null) Hibernate: CALL IDENTITY() Hibernate: select model0_.id as id, model0_.firstName as firstName, model0_.lastName as lastName, model0_.birthday as birthday, year(curdate()) - year(model0_.birthday) - casewhen(month(curdate()) * 100 + dayofmonth(curdate()) < month(model0_.birthday) * 100 + dayofmonth(model0_.birthday), 1, 0) as f0_ from MODEL model0_ onLoad() : Yuri Ebihara, 1979/10/03(24) onLoad() : Yu Yamada, 1984/07/05(19) onLoad() : Moe Oshikiri, 1979/12/29(24) Yuri Ebihara, 1979/10/03(24) Yu Yamada, 1984/07/05(19) Moe Oshikiri, 1979/12/29(24)
おっしゃー!
なんか久しぶりに「ぐはぁっ」を使わずにすんだような気が.まぁ,毎回のように使っている <property>
要素なのですから,いちいち吐血なんてしてたら出血多量で死んじゃいますよ.
ともあれ,java.util.Date
で大丈夫みたいですね.
これで getter/setter のないクラスでも大丈夫♪ 導出項目があっても大丈夫♪
ついでに getURI()
みたいな場合のプロパティ名がどうなるか試してみました.結論はやっぱり "URI"
が正解っぽい."uri"
だと PropertyNotFoundException
なる例外が吹っ飛んできました.念のため "uRI"
も試しましたがこっちはもっとひどい例外の連鎖が.どうして違うわけ? まいっか.
先頭小文字とか気にしないで,普通にJavaBeansのお約束に従えばいいみたいです.