Hibernate (1)
※注意: このドキュメントは執筆途中のため、 意味の通じない箇所等が至るところにありますが、 あらかじめご了承ください。
Hibernate (1)
Hibernate というのはあちこちで話題になっているので細かいことは省略する。 というか、既知のものとする。
collection
Hibernate のマニュアルには、 猫の例が出てくるのが有名だが、 Collection examples には Parent-Child の例が出ているから、 まず、それをそのまま素直に使ってみよう。
Hibernate は、 クラスとRDBとのマッピングファイルを使ってO/R mapping を実現している。 このマッピングファイルは XML で記述するのだが、 名前が .hbm.xml という文字列で終わるようにするのが慣例である。 ということで、今回のマッピングファイルは、 Family.hbm.xml という名前にしてみる。 内容は次のようになる。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.phinloda.practice.hibernate.Parent"> <id name="id" type="long"> <generator class="increment"/> </id> <set name="children"> <key column="parent_id"/> <one-to-many class="com.phinloda.practice.hibernate.Child"/> </set> </class> <class name="com.phinloda.practice.hibernate.Child"> <id name="id" type="long"> <generator class="increment"/> </id> <property name="name" type="string" /> </class> </hibernate-mapping>
これに対する Java のクラスは次のようになる。 コメントにも出てくるが、 このクラスは実は Hibernate の code generator を使って自動生成したものだ。
package com.phinloda.practice.hibernate; import java.io.Serializable; import java.util.Set; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Parent implements Serializable { /** identifier field */ private int id; /** persistent field */ private Set children; /** full constructor */ public Parent(Set children) { this.children = children; } /** default constructor */ public Parent() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public Set getChildren() { return this.children; } public void setChildren(Set children) { this.children = children; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } }
package com.phinloda.practice.hibernate; import java.io.Serializable; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Child implements Serializable { /** identifier field */ private int id; /** nullable persistent field */ private String name; /** full constructor */ public Child(String name, String kind) { this.name = name; } /** default constructor */ public Child() { } public int getId() { return this.id; } public void setId(int id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } }
このクラスをクラス図にしてみると、こんな感じ。
-------------- Parent -------------- - id : long - children : set -------------- + getId() : long + setId(id : int) : void + getChildren() : Set + setChildren(children : Set) : void -----------------------
-------------- Child -------------- - id : long - name : string -------------- + getId() : long + setId(id : int) : void + getName() : String + setName(name : String) : void -----------------------
---
Collection (2)
Child に parent を指定できるように拡張した例が出ているので、 動作を確認してみよう。 Mapping file を追加する。
Family2.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.phinloda.practice.hibernate.Parent2"> <id name="id" type="long"> <generator class="increment"/> </id> <set name="children"> <key column="parent_id"/> <one-to-many class="com.phinloda.practice.hibernate.Child2"/> </set> </class> <class name="com.phinloda.practice.hibernate.Child2"> <id name="id" type="long"> <generator class="increment"/> </id> <property name="name" type="string" /> <many-to-one name="parent" class="com.phinloda.practice.hibernate.Parent2" column="parent_id" not-null="true"/> </class> </hibernate-mapping>
Family.hbm.xml をちょっとだけ変更した。 Parent、Child という名前をそのまま使ってもいいのだが、 その場合は前の例が動かなくなるので、 別の名前でマッピングファイルを追加した。 この場合、 hibernate.cfg.xml にも変更が必要になる。
Buildfile: D:\java\eclipse\workspace\hibernate\build.xml codegen: [hbm2java] Processing 1 mapping files. [hbm2java] 05:18:53,413 INFO Generator:96 - Generating 3 in D:\java\eclipse\workspace\hibernate\src BUILD SUCCESSFUL Total time: 3 seconds
ant schema を実行。
Buildfile: D:\java\eclipse\workspace\hibernate\build.xml prepare: compile: schema: [schemaexport] 21:08:28,968 INFO Environment:483 - Hibernate 2.1.8 [schemaexport] 21:08:28,988 INFO Environment:517 - loaded properties from resource hibernate.properties: {hibernate.connection.username=********, hibernate.connection.password=********, hibernate.cglib.use_reflection_optimizer=false, hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect, hibernate.connection.url=jdbc:mysql://localhost/practice, hibernate.connection.driver_class=com.mysql.jdbc.Driver} [schemaexport] 21:08:28,998 INFO Environment:572 - using JDK 1.4 java.sql.Timestamp handling [schemaexport] 21:08:29,048 INFO Configuration:170 - Mapping file: D:\java\eclipse\workspace\hibernate\classes\com\phinloda\practice\hibernate\Family.hbm.xml [schemaexport] 21:08:31,010 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Parent -> Parent [schemaexport] 21:08:31,481 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Child -> Child [schemaexport] 21:08:31,481 INFO Configuration:170 - Mapping file: D:\java\eclipse\workspace\hibernate\classes\com\phinloda\practice\hibernate\Family2.hbm.xml [schemaexport] 21:08:32,803 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Parent2 -> Parent2 [schemaexport] 21:08:32,813 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Child2 -> Child2 [schemaexport] 21:08:32,903 INFO Dialect:86 - Using dialect: net.sf.hibernate.dialect.MySQLDialect [schemaexport] 21:08:32,903 INFO Configuration:641 - processing one-to-many association mappings [schemaexport] 21:08:32,933 INFO Binder:1181 - Mapping collection: com.phinloda.practice.hibernate.Parent.children -> Child [schemaexport] 21:08:32,933 INFO Binder:1181 - Mapping collection: com.phinloda.practice.hibernate.Parent2.children -> Child2 [schemaexport] 21:08:32,933 INFO Configuration:650 - processing one-to-one association property references [schemaexport] 21:08:32,943 INFO Configuration:675 - processing foreign key constraints [schemaexport] 21:08:33,073 INFO Configuration:641 - processing one-to-many association mappings [schemaexport] 21:08:33,214 INFO Configuration:650 - processing one-to-one association property references [schemaexport] 21:08:33,214 INFO Configuration:675 - processing foreign key constraints [schemaexport] 21:08:33,234 INFO SchemaExport:98 - Running hbm2ddl schema export [schemaexport] 21:08:33,234 INFO SchemaExport:117 - exporting generated schema to database [schemaexport] 21:08:33,254 INFO DriverManagerConnectionProvider:42 - Using Hibernate built-in connection pool (not for production use!) [schemaexport] 21:08:33,264 INFO DriverManagerConnectionProvider:43 - Hibernate connection pool size: 20 [schemaexport] 21:08:33,284 INFO DriverManagerConnectionProvider:77 - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/practice [schemaexport] 21:08:33,284 INFO DriverManagerConnectionProvider:78 - connection properties: {user=********, password=********} [schemaexport] alter table Child drop foreign key FK3E104FC7B66B0D0 [schemaexport] 21:08:34,385 DEBUG SchemaExport:132 - alter table Child drop foreign key FK3E104FC7B66B0D0 [schemaexport] alter table Child2 drop foreign key FK783F9AB67B66B0D0 [schemaexport] 21:08:34,596 DEBUG SchemaExport:132 - alter table Child2 drop foreign key FK783F9AB67B66B0D0 [schemaexport] drop table if exists Parent2 [schemaexport] 21:08:34,776 DEBUG SchemaExport:132 - drop table if exists Parent2 [schemaexport] drop table if exists Parent [schemaexport] 21:08:34,786 DEBUG SchemaExport:132 - drop table if exists Parent [schemaexport] drop table if exists Child [schemaexport] 21:08:34,816 DEBUG SchemaExport:132 - drop table if exists Child [schemaexport] drop table if exists Child2 [schemaexport] 21:08:34,816 DEBUG SchemaExport:132 - drop table if exists Child2 [schemaexport] create table Parent2 ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 21:08:34,826 DEBUG SchemaExport:149 - create table Parent2 ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] create table Parent ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 21:08:34,926 DEBUG SchemaExport:149 - create table Parent ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] create table Child ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] parent_id bigint, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 21:08:35,006 DEBUG SchemaExport:149 - create table Child ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] parent_id bigint, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] create table Child2 ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] parent_id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 21:08:35,126 DEBUG SchemaExport:149 - create table Child2 ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] parent_id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] alter table Child add index FK3E104FC7B66B0D0 (parent_id), add constraint FK3E104FC7B66B0D0 foreign key (parent_id) references Parent (id) [schemaexport] 21:08:35,186 DEBUG SchemaExport:149 - alter table Child add index FK3E104FC7B66B0D0 (parent_id), add constraint FK3E104FC7B66B0D0 foreign key (parent_id) references Parent (id) [schemaexport] alter table Child2 add index FK783F9AB67B66B0D0 (parent_id), add constraint FK783F9AB67B66B0D0 foreign key (parent_id) references Parent2 (id) [schemaexport] 21:08:35,287 DEBUG SchemaExport:149 - alter table Child2 add index FK783F9AB67B66B0D0 (parent_id), add constraint FK783F9AB67B66B0D0 foreign key (parent_id) references Parent2 (id) [schemaexport] 21:08:35,377 INFO SchemaExport:160 - schema export complete [schemaexport] 21:08:35,387 INFO DriverManagerConnectionProvider:143 - cleaning up connection pool: jdbc:mysql://localhost/practice BUILD SUCCESSFUL Total time: 9 seconds
これに対するテストケースを書くのだが、 まず、コピペしてちゃちゃっと修正してみる。
package com.phinloda.practice.hibernate; import java.util.HashSet; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import junit.framework.TestCase; public class FamilyTest2 extends TestCase { public static void main(String[] args) { junit.textui.TestRunner.run(FamilyTest2.class); } protected void setUp() throws Exception { super.setUp(); } protected void tearDown() throws Exception { super.tearDown(); } public final void testAll() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Transaction transaction = session.beginTransaction(); try { Parent2 parent2 = new Parent2(); parent2.setChildren(new HashSet()); Child2 child2 = new Child2(); child2.setName("John"); child2.setParent(parent2); parent2.getChildren().add(child2); session.save(parent2); session.save(child2); transaction.commit(); } catch (HibernateException he) { he.printStackTrace(); transaction.rollback(); fail(); } session.close(); } public final void testSearch() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); List result = session.createQuery("from Child").list(); showList(result); List result2 = session.createQuery( "from Child2 as child" + " where child.name='John'").list(); showList(result2); session.close(); } private void showList(List list) { if (list == null) { System.out.println("list is null"); return; } for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).toString()); } } private void showList2(List list) { if (list == null) { System.out.println("list is null"); return; } for (int i = 0; i < list.size(); i++) { System.out.print(i); System.out.print(": "); Object [] rows = (Object[]) list.get(i); for (int j = 0; j < rows.length; j++) { System.out.print(rows[j].toString()); } System.out.println(""); } } }
実行すると、こんな感じ。
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. Hibernate: select max(id) from Parent2 Hibernate: select max(id) from Child2 Hibernate: insert into Parent2 (id) values (?) Hibernate: insert into Child2 (name, parent_id, id) values (?, ?, ?) Hibernate: update Child2 set parent_id=? where id=? Hibernate: select child0_.id as id9_, child0_.name as name9_ from Child child0_ Hibernate: select child2x0_.id as id11_, child2x0_.name as name11_, child2x0_.parent_id as parent3_11_ from Child2 child2x0_ where child2x0_.name='John' com.phinloda.practice.hibernate.Child2@90832e[id=1]
これはこれでいいのだが、 1箇所変更して試してみよう。 session.save を呼び出す順序を、 次のように変更する。
session.save(child2); session.save(parent2);
実行すると、 次のように Exception が発生する。
~(略)~ org.hibernate.PropertyValueException: not-null property references a null or transient value: com.phinloda.practice.hibernate.Child2.parent at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72) ~(略)~ at com.phinloda.practice.hibernate.FamilyTest2.testAll(FamilyTest2.java:46)
発生しているのは、 次の箇所。
session.save(child2);
前後の状況を確認してみたいので、 一時的に、 Child2.java の toString() メソッドを変更する。 このように Child2.java を直接変更してしまうと、 その後、 ant codegen で上書きされて、内容が消滅するかもしれない、 という意味で「一時的」と表現した。
public String toString() { return new ToStringBuilder(this) .append("id", getId()) .append("name", getName()) .append("parent", getParent()) .toString(); }
FamilyTest2.java の、session.save の前にコードを追加する。
System.err.println(child2.toString()); session.save(child2); session.save(parent2);
com.phinloda.practice.hibernate.Child2@1884174[id=0,name=John,parent=com.phinloda.practice.hibernate.Parent2@ee6681[id=0]]
なるほど、 id=0 というのがおかしいようだ。 ということは、試しに parent2 のid を1にしてみる。
parent2.setId(1); session.save(child2); session.save(parent2);
これでエラーは解消した。
エラーは解消したが、 id をこのように明示的に指定してもいいのだろうか? mysql をコマンドラインから起動してテーブルを見ると、 ちゃんと id は修正されて保存されている。
さて、これでテストはうまく行ったが、 このテストケースはあんまりだから、 リファクタリングをしておこう。 まず、 src の下に、 Util.java を作成する。
package com.phinloda.practice.hibernate; import java.util.List; public class Util { static public void showList(List list) { if (list == null) { System.out.println("list is null"); return; } for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).toString()); } } }
FamilyTest2.java は、次のように showList の呼び出しを、 今作ったユーティリティクラスを使うように変更する。
public final void testSearch() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); List result = session.createQuery("from Child").list(); Util.showList(result); List result2 = session.createQuery( "from Child2 as child" + " where child.name='John'").list(); Util.showList(result2); session.close(); }
showList2 も Util 側に移動しておく。
package com.phinloda.practice.hibernate; import java.util.List; public class Util { static public void showList(List list) { if (list == null) { System.out.println("list is null"); return; } for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i).toString()); } } static public void showList2(List list) { if (list == null) { System.out.println("list is null"); return; } for (int i = 0; i < list.size(); i++) { System.out.print(i); System.out.print(": "); Object[] rows = (Object[]) list.get(i); for (int j = 0; j < rows.length; j++) { System.out.print(rows[j].toString()); } System.out.println(""); } } }
Collection (3)
次は、HIBERNATE のマニュアルには
if you absolutely insist that this association should be unidirectional
と書いてある例。 マニュアルでは、次のようになっている。
<hibernate-mapping> <class name="Parent"> <id name="id"> <generator class="sequence"/> </id> <set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="Child"/> </set> </class> <class name="Child"> <id name="id"> <generator class="sequence"/> </id> <property name="name"/> </class> </hibernate-mapping>
実際に使ったマッピングファイルは次のものである。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.phinloda.practice.hibernate.Parent3"> <id name="id" type="long"> <generator class="increment"/> </id> <set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="com.phinloda.practice.hibernate.Child3"/> </set> </class> <class name="com.phinloda.practice.hibernate.Child3"> <id name="id" type="long"> <generator class="increment"/> </id> <property name="name" type="string" /> </class> </hibernate-mapping>
ant codegen と、 ant schema を実行しておく。 特に問題は発生しないはず。
これに対するテストケース。 今回は既定クラスを作ることにする。 TestCaseBase.java を test ディレクトリの下に作成する。
package com.phinloda.practice.hibernate; import org.hibernate.cfg.Configuration; import junit.framework.TestCase; public class TestCaseBase extends TestCase { public static void main(String[] args) { junit.textui.TestRunner.run(TestCaseBase.class); } protected void setUp() throws Exception { super.setUp(); setCfg(new Configuration()); getCfg().configure(); } protected void tearDown() throws Exception { super.tearDown(); } private Configuration _cfg; public Configuration getCfg() { return _cfg; } public void setCfg(Configuration cfg) { this._cfg = cfg; } }
FamilyTest3.java は、これを extends するように作成する。 とはいっても、結局 FamilyTest.java の殆どパクリという状態。 まだ工夫の余地がたくさんあるのだが、 とりあえず。 余談だが、 最近この「とりあえず」というのがアジャイルの極意ではないか、 と思ったりすることがある。
package com.phinloda.practice.hibernate; import java.util.HashSet; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class FamilyTest3 extends TestCaseBase { public final void testAll() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Transaction transaction = session.beginTransaction(); try { Parent3 parent3 = new Parent3(); parent3.setChildren(new HashSet()); Child3 child3 = new Child3(); child3.setName("taro"); parent3.getChildren().add(child3); session.save(parent3); session.save(child3); child3 = new Child3(); child3.setName("Hoge"); parent3.getChildren().add(child3); session.save(parent3); session.save(child3); transaction.commit(); } catch (HibernateException he) { he.printStackTrace(); transaction.rollback(); fail(); } session.close(); } public final void testSearch() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); List result = session.createQuery("from Child").list(); Util.showList(result); List result2 = session.createQuery( "from Parent as parent" + " inner join parent.children as child" + " where child.name='Hoge'").list(); Util.showList2(result2); session.close(); } }
これはこれで普通に動作するはず。
Collection (4)
次にマニュアルに出てくるのは many-to-many association の例だ。 実際に使ったマッピングファイルは次のようになった。
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.phinloda.practice.hibernate.Parent4"> <id name="id" type="long"> <generator class="increment"/> </id> <set name="children" table="childset4"> <key column="parent_id"/> <many-to-many class="com.phinloda.practice.hibernate.Child4" column="child_id" /> </set> </class> <class name="com.phinloda.practice.hibernate.Child4"> <id name="id" type="long"> <generator class="increment"/> </id> <property name="name" type="string" /> </class> </hibernate-mapping>
生成されたソースは次のようになっている。
package com.phinloda.practice.hibernate; import java.io.Serializable; import java.util.Set; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Parent4 implements Serializable { /** identifier field */ private long id; /** persistent field */ private Set children; /** full constructor */ public Parent4(Set children) { this.children = children; } /** default constructor */ public Parent4() { } public long getId() { return this.id; } public void setId(long id) { this.id = id; } public Set getChildren() { return this.children; } public void setChildren(Set children) { this.children = children; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } }
package com.phinloda.practice.hibernate; import java.io.Serializable; import org.apache.commons.lang.builder.ToStringBuilder; /** @author Hibernate CodeGenerator */ public class Child4 implements Serializable { /** identifier field */ private long id; /** nullable persistent field */ private String name; /** full constructor */ public Child4(String name) { this.name = name; } /** default constructor */ public Child4() { } public long getId() { return this.id; } public void setId(long id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public String toString() { return new ToStringBuilder(this) .append("id", getId()) .toString(); } }
最初の例と変わらないようだが、 とりあえず次に進もう。
ant schema を実行すると、 次のように表示された。
Buildfile: D:\java\eclipse\workspace\hibernate\build.xml prepare: [copy] Copying 1 file to D:\java\eclipse\workspace\hibernate\classes compile: [javac] Compiling 8 source files to D:\java\eclipse\workspace\hibernate\classes schema: [schemaexport] 02:55:26,727 INFO Environment:483 - Hibernate 2.1.8 [schemaexport] 02:55:26,737 INFO Environment:517 - loaded properties from resource hibernate.properties: {hibernate.connection.username=********, hibernate.connection.password=********, hibernate.cglib.use_reflection_optimizer=false, hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect, hibernate.connection.url=jdbc:mysql://localhost/practice, hibernate.connection.driver_class=com.mysql.jdbc.Driver} [schemaexport] 02:55:26,737 INFO Environment:572 - using JDK 1.4 java.sql.Timestamp handling ~(略)~ [schemaexport] 02:55:30,562 INFO Configuration:170 - Mapping file: D:\java\eclipse\workspace\hibernate\classes\com\phinloda\practice\hibernate\family4.hbm.xml [schemaexport] 02:55:31,634 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Parent4 -> Parent4 [schemaexport] 02:55:31,634 INFO Binder:571 - Mapping collection: com.phinloda.practice.hibernate.Parent4.children -> childset4 [schemaexport] 02:55:31,644 INFO Binder:229 - Mapping class: com.phinloda.practice.hibernate.Child4 -> Child4 [schemaexport] 02:55:31,724 INFO Dialect:86 - Using dialect: net.sf.hibernate.dialect.MySQLDialect [schemaexport] 02:55:31,734 INFO Configuration:641 - processing one-to-many association mappings ~(略)~ [schemaexport] 02:55:31,744 INFO Configuration:650 - processing one-to-one association property references [schemaexport] 02:55:31,744 INFO Configuration:675 - processing foreign key constraints [schemaexport] 02:55:31,864 INFO Configuration:641 - processing one-to-many association mappings [schemaexport] 02:55:31,864 INFO Configuration:650 - processing one-to-one association property references [schemaexport] 02:55:31,864 INFO Configuration:675 - processing foreign key constraints [schemaexport] 02:55:31,884 INFO SchemaExport:98 - Running hbm2ddl schema export [schemaexport] 02:55:31,884 INFO SchemaExport:117 - exporting generated schema to database [schemaexport] 02:55:31,904 INFO DriverManagerConnectionProvider:42 - Using Hibernate built-in connection pool (not for production use!) [schemaexport] 02:55:31,904 INFO DriverManagerConnectionProvider:43 - Hibernate connection pool size: 20 [schemaexport] 02:55:31,914 INFO DriverManagerConnectionProvider:77 - using driver: com.mysql.jdbc.Driver at URL: jdbc:mysql://localhost/practice [schemaexport] 02:55:31,914 INFO DriverManagerConnectionProvider:78 - connection properties: {user=********, password=********} [schemaexport] alter table childset4 drop foreign key FKFA61D72E62EA171E [schemaexport] 02:55:32,395 DEBUG SchemaExport:132 - alter table childset4 drop foreign key FKFA61D72E62EA171E [schemaexport] 02:55:32,435 DEBUG SchemaExport:137 - Unsuccessful: alter table childset4 drop foreign key FKFA61D72E62EA171E [schemaexport] 02:55:32,435 DEBUG SchemaExport:138 - Table 'practice.childset4' doesn't exist [schemaexport] alter table childset4 drop foreign key FKFA61D72E7B66B0D0 [schemaexport] 02:55:32,435 DEBUG SchemaExport:132 - alter table childset4 drop foreign key FKFA61D72E7B66B0D0 [schemaexport] 02:55:32,445 DEBUG SchemaExport:137 - Unsuccessful: alter table childset4 drop foreign key FKFA61D72E7B66B0D0 [schemaexport] 02:55:32,445 DEBUG SchemaExport:138 - Table 'practice.childset4' doesn't exist ~(略)~ [schemaexport] drop table if exists childset4 [schemaexport] 02:55:32,736 DEBUG SchemaExport:132 - drop table if exists childset4 [schemaexport] drop table if exists Parent4 [schemaexport] 02:55:32,746 DEBUG SchemaExport:132 - drop table if exists Parent4 ~(略)~ [schemaexport] drop table if exists Child4 [schemaexport] 02:55:32,756 DEBUG SchemaExport:132 - drop table if exists Child4 ~(略)~ [schemaexport] create table childset4 ( [schemaexport] parent_id bigint not null, [schemaexport] child_id bigint not null, [schemaexport] primary key (parent_id, child_id) [schemaexport] ) [schemaexport] 02:55:32,766 DEBUG SchemaExport:149 - create table childset4 ( [schemaexport] parent_id bigint not null, [schemaexport] child_id bigint not null, [schemaexport] primary key (parent_id, child_id) [schemaexport] ) ~(略)~ [schemaexport] create table Parent4 ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 02:55:33,116 DEBUG SchemaExport:149 - create table Parent4 ( [schemaexport] id bigint not null, [schemaexport] primary key (id) [schemaexport] ) ~(略)~ [schemaexport] create table Child4 ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] primary key (id) [schemaexport] ) [schemaexport] 02:55:33,366 DEBUG SchemaExport:149 - create table Child4 ( [schemaexport] id bigint not null, [schemaexport] name varchar(255), [schemaexport] primary key (id) [schemaexport] ) ~(略)~ [schemaexport] alter table childset4 add index FKFA61D72E62EA171E (child_id), add constraint FKFA61D72E62EA171E foreign key (child_id) references Child4 (id) [schemaexport] 02:55:33,677 DEBUG SchemaExport:149 - alter table childset4 add index FKFA61D72E62EA171E (child_id), add constraint FKFA61D72E62EA171E foreign key (child_id) references Child4 (id) [schemaexport] alter table childset4 add index FKFA61D72E7B66B0D0 (parent_id), add constraint FKFA61D72E7B66B0D0 foreign key (parent_id) references Parent4 (id) [schemaexport] 02:55:33,807 DEBUG SchemaExport:149 - alter table childset4 add index FKFA61D72E7B66B0D0 (parent_id), add constraint FKFA61D72E7B66B0D0 foreign key (parent_id) references Parent4 (id) ~(略)~ [schemaexport] 02:55:34,138 INFO SchemaExport:160 - schema export complete [schemaexport] 02:55:34,148 INFO DriverManagerConnectionProvider:143 - cleaning up connection pool: jdbc:mysql://localhost/practice BUILD SUCCESSFUL Total time: 9 seconds
ポイントは childset4 というテーブルで、 これを使って many-to-many の関係が表現されているのである。
hibernate プロジェクトを refresh して、 テストケースを作成する。
package com.phinloda.practice.hibernate; import java.util.HashSet; import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; public class FamilyTest4 extends TestCaseBase { public final void testAll() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); Transaction transaction = session.beginTransaction(); try { Parent4 parent4_1 = new Parent4(); parent4_1.setChildren(new HashSet()); Child4 child4 = new Child4(); child4.setName("taro"); parent4_1.getChildren().add(child4); session.save(parent4_1); session.save(child4); Parent4 parent4_2 = new Parent4(); parent4_2.setChildren(new HashSet()); parent4_2.getChildren().add(child4); session.save(parent4_2); session.save(child4); transaction.commit(); } catch (HibernateException he) { he.printStackTrace(); transaction.rollback(); fail(); } session.close(); } public final void testSearch() { Configuration cfg = new Configuration(); cfg.configure(); SessionFactory factory = cfg.buildSessionFactory(); Session session = factory.openSession(); List result = session.createQuery("from Child4").list(); Util.showList(result); List result2 = session.createQuery( "from Parent4 as parent" + " inner join parent.children as child" + " where child.name='taro'").list(); Util.showList2(result2); session.close(); } }
Collection (5)
※UNDER CONSTRUCTION -- この箇所、執筆中です