精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-05-07
最后修改:2008-11-12
接上篇 hibernate入门使用系列 2-- xml关系映射篇(上) 上篇讲了1:1,那么这次继续讲1:n和n:1。 这次用到的例子是Father和child之间的关系。一个father可以有n个child,但是1个child只有一个father。这里只说生父。至于其他的继父、养父、干爹等等,不再范围之内。 好吧。还是同前面的一样。现建立实体模型如下:
根据模型创建数据库。sql脚本如下: use HibernateQuickUse; drop table if exists Child; drop table if exists Father; create table Father ( id varchar(32) primary key, name varchar(32) not null ); create table Child ( id varchar(32) primary key, name varchar(128) not null, father_id varchar(32) not null, foreign key(father_id) references Father(id) );
根据模型创建java对象。 Father.java: package org.py.hib.relation.one2many; import java.util.HashSet; import java.util.Set; /** * Father entity. */ @SuppressWarnings("serial") public class Father implements java.io.Serializable { private String id; private String name; private Set<Child> children = new HashSet<Child>(0); public Father() { } public String getId() { return this.id; } public void setId(String id) { this.id = id; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } public Set<Child> getChildren() { return children; } public void setChildren(Set<Child> children) { this.children = children; } }
Child.java: package org.py.hib.relation.one2many; /** * Child entity. * @author MyEclipse Persistence Tools */ @SuppressWarnings("serial") public class Child implements java.io.Serializable { private String id; private String name; private Father father; public Child() { } public String getId() { return this.id; } public void setId(String id) { this.id = id; } public Father getFather() { return this.father; } public void setFather(Father father) { this.father = father; } public String getName() { return this.name; } public void setName(String name) { this.name = name; } }
映射文件如下: Father.hbm.xml: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="org.py.hib.relation.one2many.Father" table="father"> <id name="id" type="java.lang.String" column="id" length="32"> <generator class="uuid" /> </id> <property name="name" type="java.lang.String" column="name" length="32" not-null="true"/> <set name="children" table="child" cascade="all" inverse="true"> <key column="father_id" /> <one-to-many class="org.py.hib.relation.one2many.Child" /> </set> </class> </hibernate-mapping> 这里要说说 "set" 这个标签里面的内容。 "name"是Father里面的属性的名字。 "table"表示它对应的是数据库中的哪个表。 cascade="all" 表示所有的操作都级联操作。 "inverse"表示关系的维护由谁来执行。true表示不由自己执行,而有对应的另外一方执行。false则相反,表示由自己维护关系。这里设置成 true 是由原因的。如果说把它设置成为false,那么就由他来维护关系了。 这里得说一下inverse属性的问题。在one-to-many中,如果关系由one来维护,那么会很麻烦,性能也会很低。每次对many一方的一条记录进行增、删、改 时都会多一次update操作。原因很简单,因为关系的维护设置在了one这一方,所以对many的每一次操作,one这一方都要维护一次双方的关系。 这个就好像皇帝和老百姓的关系。试问,是来一个老百姓,皇帝就宣布他是我的子民,还是由老百姓直接选择做那个皇帝的子民更加有效率呢?呵呵。不知道这个例子大家有没有明白。关于inverse的更具体的说明,在javaeye上搜一下,就会发现有很多。这里推荐一篇,我认为讲得很明白的:主题:inverse。 "key" 中的 "column" 表示在table(这里的table是child)中, 跟Father关联的字段名称。这里是"father_id"。可以看看开始的sql脚本。 one-to-many 表示father和children的关系。class则表示是同哪个类是这种关系。
Child.hbm.xml: <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="org.py.hib.relation.one2many.Child" table="child"> <id name="id" type="java.lang.String" column="id" length="32" > <generator class="uuid" /> </id> <property name="name" type="java.lang.String" column="name" length="128" not-null="true"/> <many-to-one name="father" class="org.py.hib.relation.one2many.Father" column="father_id" /> </class> </hibernate-mapping> 这个里面主要就是多了一个many-to-one,表示child 和 father 的关系是"many-to-one"
测试代码如下: One2ManyTest.java package org.py.hib.relation.one2many; import java.util.Set; import junit.framework.Assert; import junit.framework.TestCase; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import org.junit.After; import org.junit.Before; public class One2ManyTest extends TestCase { private SessionFactory factory; private static final String[] childname = new String[] { "child_1", "child_2", "child_3" }; private static final String[] newchildname = new String[] { "new_child_1", "new_child_2", "new_child_3" }; @Before public void setUp() throws Exception { Configuration conf = new Configuration().configure(); factory = conf.buildSessionFactory(); } /** * 测试添加 * @throws Exception */ public void testSave() throws Exception { System.out.println("\n=== test save ==="); Father father = new Father(); father.setName("Father_1"); Child child1 = new Child(); child1.setName(childname[0]); Child child2 = new Child(); child2.setName(childname[1]); Child child3 = new Child(); child3.setName(childname[2]); father.getChildren().add(child1); father.getChildren().add(child2); father.getChildren().add(child3); child1.setFather(father); child2.setFather(father); child3.setFather(father); Session session = null; Transaction tran = null; try { session = factory.openSession(); tran = session.beginTransaction(); session.save(father); tran.commit(); Assert.assertNotNull(father.getId()); Assert.assertNotNull(child1.getId()); Assert.assertNotNull(child2.getId()); Assert.assertNotNull(child3.getId()); } catch (Exception ex) { tran.rollback(); throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } } private boolean isChildrenName(String name) { for (String n : childname) { if (n.equals(name)) return true; } return false; } private boolean isNewChildrenName(String name) { for (String n : newchildname) { if (n.equals(name)) return true; } return false; } /** * 测试查询 * @throws Exception */ public void testFind() throws Exception { System.out.println("\n=== test find ==="); Session session = null; try { session = factory.openSession(); Father father = (Father) session.createQuery("from Father").list().get(0); Assert.assertNotNull(father.getId()); Assert.assertEquals("Father_1", father.getName()); Set<Child> children = father.getChildren(); for (Child child : children) { Assert.assertEquals(child.getFather(), father); Assert.assertNotNull(child.getId()); Assert.assertTrue(isChildrenName(child.getName())); } } catch (Exception ex) { throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } } /** * 测试修改 * @throws Exception */ public void testModify() throws Exception { System.out.println("\n=== test modify ==="); Session session = null; Transaction tran = null; try { session = factory.openSession(); tran = session.beginTransaction(); Father father = (Father) session.createQuery("from Father").list().get(0); father.setName("Father_2"); // 修改用户名 = m_name2.(原来用户名= m_name) Set<Child> children = father.getChildren(); int i = 0; for (Child child : children) { child.setName(newchildname[i++]); } tran.commit(); } catch (Exception ex) { throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } /* * 修改后再查询 */ System.out.println("\n=== test find after modify ==="); try { session = factory.openSession(); Father father = (Father) session.createQuery("from Father").list().get(0); Assert.assertNotNull(father.getId()); Assert.assertEquals("Father_2", father.getName()); Set<Child> children = father.getChildren(); for (Child child : children) { Assert.assertEquals(child.getFather(), father); Assert.assertNotNull(child.getId()); Assert.assertTrue(isNewChildrenName(child.getName())); } } catch (Exception ex) { throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } } /** * 测试删除 * @throws Exception */ public void testDelete() throws Exception { System.out.println("\n=== test delete ==="); Session session = null; Transaction tran = null; try { session = factory.openSession(); tran = session.beginTransaction(); Father father = (Father) session.createQuery("from Father").list().get(0); session.delete(father); tran.commit(); } catch (Exception ex) { throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } /* * 删除后再查询 */ System.out.println("\n=== test find after delete ==="); try { session = factory.openSession(); Integer num = (Integer) session.createQuery("from Father").list().size(); Assert.assertEquals(0, num.intValue()); num = (Integer) session.createQuery("from Child").list().size(); Assert.assertEquals(0, num.intValue()); } catch (Exception ex) { throw ex; } finally { if (session != null) { try { session.close(); } catch (Exception ex) { // nothing to do } finally { if (session != null) session = null; } } } } /** * */ @After public void tearDown() throws Exception { factory.close(); } } 这里不得不再重申以下 one-to-many 中 inverse 关系的维护问题。 在one-to-many中,把inverse放到many中来维护是一个好的习惯。大家可以把上面的inverse改成false,看看会发生什么情况。 在inverse=true的时候,输出结果如下: === test save === Hibernate: insert into father (name, id) values (?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) === test find === Hibernate: select father0_.id as id13_, father0_.name as name13_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id14_0_, children0_.name as name14_0_, children0_.father_id as father3_14_0_ from child children0_ where children0_.father_id=? === test modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? Hibernate: update father set name=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? === test find after modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? === test delete === Hibernate: select father0_.id as id33_, father0_.name as name33_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id34_0_, children0_.name as name34_0_, children0_.father_id as father3_34_0_ from child children0_ where children0_.father_id=? Hibernate: delete from child where id=? Hibernate: delete from child where id=? Hibernate: delete from child where id=? Hibernate: delete from father where id=? === test find after delete === Hibernate: select father0_.id as id33_, father0_.name as name33_ from father father0_ Hibernate: select child0_.id as id34_, child0_.name as name34_, child0_.father_id as father3_34_ from child child0_ 而改成 inverse=false后,testDelete()是没法通过的。输出如下: log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. === test save === Hibernate: insert into father (name, id) values (?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: update child set father_id=? where id=? Hibernate: update child set father_id=? where id=? Hibernate: update child set father_id=? where id=? === test find === Hibernate: select father0_.id as id13_, father0_.name as name13_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id14_0_, children0_.name as name14_0_, children0_.father_id as father3_14_0_ from child children0_ where children0_.father_id=? === test modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? Hibernate: update father set name=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? === test find after modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? === test delete === Hibernate: select father0_.id as id33_, father0_.name as name33_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id34_0_, children0_.name as name34_0_, children0_.father_id as father3_34_0_ from child children0_ where children0_.father_id=? Hibernate: update child set father_id=null where father_id=? 错误信息如下:
具体的出错原因是:违反了非空约束。 得修改sql脚本,把Child的建表脚本中的: father_id varchar(32) not null, 修改成为:father_id varchar(32), 才能通过。这个时候输出的结果是: log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment). log4j:WARN Please initialize the log4j system properly. === test save === Hibernate: insert into father (name, id) values (?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: insert into child (name, father_id, id) values (?, ?, ?) Hibernate: update child set father_id=? where id=? Hibernate: update child set father_id=? where id=? Hibernate: update child set father_id=? where id=? === test find === Hibernate: select father0_.id as id13_, father0_.name as name13_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id14_0_, children0_.name as name14_0_, children0_.father_id as father3_14_0_ from child children0_ where children0_.father_id=? === test modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? Hibernate: update father set name=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? Hibernate: update child set name=?, father_id=? where id=? === test find after modify === Hibernate: select father0_.id as id23_, father0_.name as name23_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id24_0_, children0_.name as name24_0_, children0_.father_id as father3_24_0_ from child children0_ where children0_.father_id=? === test delete === Hibernate: select father0_.id as id33_, father0_.name as name33_ from father father0_ Hibernate: select children0_.father_id as father3_1_, children0_.id as id1_, children0_.id as id34_0_, children0_.name as name34_0_, children0_.father_id as father3_34_0_ from child children0_ where children0_.father_id=? Hibernate: update child set father_id=null where father_id=? Hibernate: delete from child where id=? Hibernate: delete from child where id=? Hibernate: delete from child where id=? Hibernate: delete from father where id=? === test find after delete === Hibernate: select father0_.id as id33_, father0_.name as name33_ from father father0_ Hibernate: select child0_.id as id34_, child0_.name as name34_, child0_.father_id as father3_34_ from child child0_ 所以,inverse的设置是很重要的一个事情。 附件中包含了源代码。这里说明一下。源代码中没有包含数据库驱动的jar包和hibernate3.1的jar包。需要大家自己添加。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-05-10
在这种one to many 的双向关联中,按照需求,更符合Hibernate的作法是还要在你的 Child 映射文件的关联中加上not-null="true"的约束。 如果是单向的one to many 关联(没有Child 到Parent 的关联),这个约束可以加在Parent的映射文件的set定义中去。 |
|
返回顶楼 | |
发表时间:2008-05-27
你好。最近遇到个问题。也是一对多双向关联的问题,举例
一个题目可以有a。b。c。d四个选项。题目类:subject 选项类 chooseItem 用户第一次建立题目是 可能是这样、 那个省人口最多 A.河南 B.河北 C.湖北 D.湖南 ok。保存入库,但用户下次修改时 可能如下 那个省人口最多 A.河南 B.河北 注意:只剩下两个选项 到此,此时的操作应该包括删除和修改多方的操作,这个hibernate能自动处理吗?该怎么处理?请赐教 |
|
返回顶楼 | |
发表时间:2008-06-16
请问下 ···
我要是实现自定义表的字段···怎么实现咯 ·· 他们的数据能进行查进去 么 ,因为表的关联是一下子取(通SET与GET)全部的数据··· 会报SQL语句的异常··· |
|
返回顶楼 | |
发表时间:2008-06-17
e3002 写道 你好。最近遇到个问题。也是一对多双向关联的问题,举例
一个题目可以有a。b。c。d四个选项。题目类:subject 选项类 chooseItem 用户第一次建立题目是 可能是这样、 那个省人口最多 A.河南 B.河北 C.湖北 D.湖南 ok。保存入库,但用户下次修改时 可能如下 那个省人口最多 A.河南 B.河北 注意:只剩下两个选项 到此,此时的操作应该包括删除和修改多方的操作,这个hibernate能自动处理吗?该怎么处理?请赐教 完全可以。看帖子里面的测试代码。里面有完整的增删该查。你可以仿照从而写出你的业务逻辑。 |
|
返回顶楼 | |
发表时间:2008-06-17
wm920 写道 我要是实现自定义表的字段···怎么实现咯 ·· 不明白什么叫自定义表的字段。能否举一例? wm920 写道 他们的数据能进行查进去 么 ,因为表的关联是一下子取(通SET与GET)全部的数据··· 会报SQL语句的异常 表的关联可以不一下子全取。hibernate提供了 延迟处理。3版本后默认为lazy。 关于lazy的用法参看这个,http://www.hibernate.org/162.html |
|
返回顶楼 | |
发表时间:2008-10-24
Exception in thread "main" java.lang.ClassCastException: java.util.ArrayList
我的程序中出现这个错误,是什么意思?请教一下 我用的是一对多关系映射,一的这方用的是List集合 |
|
返回顶楼 | |
发表时间:2008-10-30
一个问题:
现在你例子中是双向关联, 也就是说child类有对father类的引向, 这样在Child.hbm.xml中就有了<many-to-one name="father" class="org.py.hib.relation.one2many.Father" column="father_id" />, 这里的inverse是默认为false的. 这时两表间的引用由child类的setFather触发. 若业务要求为单向关联,也就是说在child这边不再有father的引用, 这样一来两表间的关联关系只能由father类来维护了, 当然在<set name="children" table="child" cascade="all" >里的inverse默认为false的, 可这样做效率上是受影响的: 当加child集合时hibernate得去检查看哪个child与father的关系有改变, 而假若由child这边来维护的话,就不会有这样效率方面的问题. 可在child的配置里若没有对father的引用后,我们也就无从下手了,不能两全其美. |
|
返回顶楼 | |
发表时间:2008-11-05
这个例子经常见到,很容易理解,很好的例子~·
|
|
返回顶楼 | |
发表时间:2008-12-04
能不能写一个用DetachedCriteria进行查询的例子呢?谢谢了!
|
|
返回顶楼 | |
浏览 8481 次